1 /* GIO - GLib Input, Output and Streaming Library 2 * 3 * Copyright (C) 2006-2007 Red Hat, Inc. 4 * Copyright (C) 2008 Novell, Inc. 5 * 6 * This library 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 of the License, or (at your option) any later version. 10 * 11 * This library 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 17 * Public License along with this library; if not, write to the 18 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, 19 * Boston, MA 02111-1307, USA. 20 * 21 * Author: Alexander Larsson <alexl (at) redhat.com> 22 * Author: Tor Lillqvist <tml (at) novell.com> 23 */ 24 25 #include "config.h" 26 27 #include <stdio.h> 28 #include <string.h> 29 #include <wchar.h> 30 31 #include "gfile.h" 32 #include "gfileattribute.h" 33 #include "gfileinfo.h" 34 #include "gwinhttpfile.h" 35 #include "gwinhttpfileinputstream.h" 36 #include "gwinhttpfileoutputstream.h" 37 #include "gioerror.h" 38 39 #include "glibintl.h" 40 41 #include "gioalias.h" 42 43 static void g_winhttp_file_file_iface_init (GFileIface *iface); 44 45 #define g_winhttp_file_get_type _g_winhttp_file_get_type 46 G_DEFINE_TYPE_WITH_CODE (GWinHttpFile, g_winhttp_file, G_TYPE_OBJECT, 47 G_IMPLEMENT_INTERFACE (G_TYPE_FILE, 48 g_winhttp_file_file_iface_init)) 49 50 static void 51 g_winhttp_file_finalize (GObject *object) 52 { 53 GWinHttpFile *file; 54 55 file = G_WINHTTP_FILE (object); 56 57 g_free (file->url.lpszScheme); 58 g_free (file->url.lpszHostName); 59 g_free (file->url.lpszUserName); 60 g_free (file->url.lpszPassword); 61 g_free (file->url.lpszUrlPath); 62 g_free (file->url.lpszExtraInfo); 63 64 g_object_unref (file->vfs); 65 66 G_OBJECT_CLASS (g_winhttp_file_parent_class)->finalize (object); 67 } 68 69 static void 70 g_winhttp_file_class_init (GWinHttpFileClass *klass) 71 { 72 GObjectClass *gobject_class = G_OBJECT_CLASS (klass); 73 74 gobject_class->finalize = g_winhttp_file_finalize; 75 } 76 77 static void 78 g_winhttp_file_init (GWinHttpFile *winhttp) 79 { 80 } 81 82 /** 83 * _g_winhttp_file_new: 84 * @vfs: GWinHttpVfs to use 85 * @uri: URI of the GWinHttpFile to create. 86 * 87 * Returns: new winhttp #GFile. 88 **/ 89 GFile * 90 _g_winhttp_file_new (GWinHttpVfs *vfs, 91 const char *uri) 92 { 93 wchar_t *wuri; 94 GWinHttpFile *file; 95 96 wuri = g_utf8_to_utf16 (uri, -1, NULL, NULL, NULL); 97 98 if (wuri == NULL) 99 return NULL; 100 101 file = g_object_new (G_TYPE_WINHTTP_FILE, NULL); 102 file->vfs = g_object_ref (vfs); 103 104 memset (&file->url, 0, sizeof (file->url)); 105 file->url.dwStructSize = sizeof (file->url); 106 file->url.dwSchemeLength = 1; 107 file->url.dwHostNameLength = 1; 108 file->url.dwUserNameLength = 1; 109 file->url.dwPasswordLength = 1; 110 file->url.dwUrlPathLength = 1; 111 file->url.dwExtraInfoLength = 1; 112 113 if (!G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpCrackUrl (wuri, 0, 0, &file->url)) 114 { 115 g_free (wuri); 116 return NULL; 117 } 118 119 file->url.lpszScheme = g_new (wchar_t, ++file->url.dwSchemeLength); 120 file->url.lpszHostName = g_new (wchar_t, ++file->url.dwHostNameLength); 121 file->url.lpszUserName = g_new (wchar_t, ++file->url.dwUserNameLength); 122 file->url.lpszPassword = g_new (wchar_t, ++file->url.dwPasswordLength); 123 file->url.lpszUrlPath = g_new (wchar_t, ++file->url.dwUrlPathLength); 124 file->url.lpszExtraInfo = g_new (wchar_t, ++file->url.dwExtraInfoLength); 125 126 if (!G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpCrackUrl (wuri, 0, 0, &file->url)) 127 { 128 g_free (file->url.lpszScheme); 129 g_free (file->url.lpszHostName); 130 g_free (file->url.lpszUserName); 131 g_free (file->url.lpszPassword); 132 g_free (file->url.lpszUrlPath); 133 g_free (file->url.lpszExtraInfo); 134 g_free (wuri); 135 return NULL; 136 } 137 138 g_free (wuri); 139 return G_FILE (file); 140 } 141 142 static gboolean 143 g_winhttp_file_is_native (GFile *file) 144 { 145 return FALSE; 146 } 147 148 static gboolean 149 g_winhttp_file_has_uri_scheme (GFile *file, 150 const char *uri_scheme) 151 { 152 return (g_ascii_strcasecmp (uri_scheme, "http") == 0 || 153 g_ascii_strcasecmp (uri_scheme, "https") == 0); 154 } 155 156 static char * 157 g_winhttp_file_get_uri_scheme (GFile *file) 158 { 159 GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file); 160 161 return g_utf16_to_utf8 (winhttp_file->url.lpszScheme, -1, NULL, NULL, NULL); 162 } 163 164 static char * 165 g_winhttp_file_get_basename (GFile *file) 166 { 167 GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file); 168 char *basename; 169 char *last_slash; 170 char *retval; 171 172 basename = g_utf16_to_utf8 (winhttp_file->url.lpszUrlPath, -1, NULL, NULL, NULL); 173 last_slash = strrchr (basename, '/'); 174 /* If no slash, or only "/" fallback to full path part of URI */ 175 if (last_slash == NULL || last_slash[1] == '\0') 176 return basename; 177 178 retval = g_strdup (last_slash + 1); 179 g_free (basename); 180 181 return retval; 182 } 183 184 static char * 185 g_winhttp_file_get_path (GFile *file) 186 { 187 return NULL; 188 } 189 190 static char * 191 g_winhttp_file_get_uri (GFile *file) 192 { 193 GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file); 194 DWORD len; 195 wchar_t *wuri; 196 char *retval; 197 198 len = 0; 199 if (!G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->funcs->pWinHttpCreateUrl (&winhttp_file->url, ICU_ESCAPE, NULL, &len) && 200 GetLastError () != ERROR_INSUFFICIENT_BUFFER) 201 return NULL; 202 203 wuri = g_new (wchar_t, ++len); 204 205 if (!G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->funcs->pWinHttpCreateUrl (&winhttp_file->url, ICU_ESCAPE, wuri, &len)) 206 { 207 g_free (wuri); 208 return NULL; 209 } 210 211 retval = g_utf16_to_utf8 (wuri, -1, NULL, NULL, NULL); 212 g_free (wuri); 213 214 if (g_str_has_prefix (retval, "http://:@")) 215 { 216 memmove (retval + 7, retval + 9, strlen (retval) - 9); 217 retval[strlen (retval) - 2] = '\0'; 218 } 219 else if (g_str_has_prefix (retval, "https://:@")) 220 { 221 memmove (retval + 8, retval + 10, strlen (retval) - 10); 222 retval[strlen (retval) - 2] = '\0'; 223 } 224 225 return retval; 226 } 227 228 static char * 229 g_winhttp_file_get_parse_name (GFile *file) 230 { 231 /* FIXME: More hair surely needed */ 232 233 return g_winhttp_file_get_uri (file); 234 } 235 236 static GFile * 237 g_winhttp_file_get_parent (GFile *file) 238 { 239 GWinHttpFile *winhttp_file; 240 char *uri; 241 char *last_slash; 242 GFile *parent; 243 244 winhttp_file = G_WINHTTP_FILE (file); 245 246 uri = g_winhttp_file_get_uri (file); 247 if (uri == NULL) 248 return NULL; 249 250 last_slash = strrchr (uri, '/'); 251 if (last_slash == NULL || *(last_slash+1) == 0) 252 { 253 g_free (uri); 254 return NULL; 255 } 256 257 while (last_slash > uri && *last_slash == '/') 258 last_slash--; 259 260 last_slash[1] = '\0'; 261 262 parent = _g_winhttp_file_new (winhttp_file->vfs, uri); 263 g_free (uri); 264 265 return parent; 266 } 267 268 static GFile * 269 g_winhttp_file_dup (GFile *file) 270 { 271 GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file); 272 char *uri = g_winhttp_file_get_uri (file); 273 GFile *retval = _g_winhttp_file_new (winhttp_file->vfs, uri); 274 275 g_free (uri); 276 277 return retval; 278 } 279 280 static guint 281 g_winhttp_file_hash (GFile *file) 282 { 283 char *uri = g_winhttp_file_get_uri (file); 284 guint retval = g_str_hash (uri); 285 286 g_free (uri); 287 288 return retval; 289 } 290 291 static gboolean 292 g_winhttp_file_equal (GFile *file1, 293 GFile *file2) 294 { 295 char *uri1 = g_winhttp_file_get_uri (file1); 296 char *uri2 = g_winhttp_file_get_uri (file2); 297 gboolean retval = g_str_equal (uri1, uri2); 298 299 g_free (uri1); 300 g_free (uri2); 301 302 return retval; 303 } 304 305 static const char * 306 match_prefix (const char *path, 307 const char *prefix) 308 { 309 int prefix_len; 310 311 prefix_len = strlen (prefix); 312 if (strncmp (path, prefix, prefix_len) != 0) 313 return NULL; 314 315 if (prefix_len > 0 && prefix[prefix_len-1] == '/') 316 prefix_len--; 317 318 return path + prefix_len; 319 } 320 321 static gboolean 322 g_winhttp_file_prefix_matches (GFile *parent, 323 GFile *descendant) 324 { 325 char *parent_uri = g_winhttp_file_get_uri (parent); 326 char *descendant_uri = g_winhttp_file_get_uri (descendant); 327 const char *remainder; 328 gboolean retval; 329 330 remainder = match_prefix (descendant_uri, parent_uri); 331 332 if (remainder != NULL && *remainder == '/') 333 retval = TRUE; 334 else 335 retval = FALSE; 336 337 g_free (parent_uri); 338 g_free (descendant_uri); 339 340 return retval; 341 } 342 343 static char * 344 g_winhttp_file_get_relative_path (GFile *parent, 345 GFile *descendant) 346 { 347 char *parent_uri = g_winhttp_file_get_uri (parent); 348 char *descendant_uri = g_winhttp_file_get_uri (descendant); 349 const char *remainder; 350 char *retval; 351 352 remainder = match_prefix (descendant_uri, parent_uri); 353 354 if (remainder != NULL && *remainder == '/') 355 retval = g_strdup (remainder + 1); 356 else 357 retval = NULL; 358 359 g_free (parent_uri); 360 g_free (descendant_uri); 361 362 return retval; 363 } 364 365 static GFile * 366 g_winhttp_file_resolve_relative_path (GFile *file, 367 const char *relative_path) 368 { 369 GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file); 370 GWinHttpFile *child; 371 wchar_t *wnew_path = g_utf8_to_utf16 (relative_path, -1, NULL, NULL, NULL); 372 373 if (wnew_path == NULL) 374 return NULL; 375 376 if (*wnew_path != '/') 377 { 378 wchar_t *tmp = g_new (wchar_t, wcslen (winhttp_file->url.lpszUrlPath) + 1 + wcslen (wnew_path) + 1); 379 wcscpy (tmp, winhttp_file->url.lpszUrlPath); 380 wcscat (tmp, L"/"); 381 wcscat (tmp, wnew_path); 382 383 g_free (wnew_path); 384 wnew_path = tmp; 385 } 386 387 child = g_object_new (G_TYPE_WINHTTP_FILE, NULL); 388 child->vfs = winhttp_file->vfs; 389 child->url = winhttp_file->url; 390 child->url.lpszScheme = g_memdup (winhttp_file->url.lpszScheme, (winhttp_file->url.dwSchemeLength+1)*2); 391 child->url.lpszHostName = g_memdup (winhttp_file->url.lpszHostName, (winhttp_file->url.dwHostNameLength+1)*2); 392 child->url.lpszUserName = g_memdup (winhttp_file->url.lpszUserName, (winhttp_file->url.dwUserNameLength+1)*2); 393 child->url.lpszPassword = g_memdup (winhttp_file->url.lpszPassword, (winhttp_file->url.dwPasswordLength+1)*2); 394 child->url.lpszUrlPath = wnew_path; 395 child->url.dwUrlPathLength = wcslen (wnew_path); 396 child->url.lpszExtraInfo = NULL; 397 child->url.dwExtraInfoLength = 0; 398 399 return (GFile *) child; 400 } 401 402 static GFile * 403 g_winhttp_file_get_child_for_display_name (GFile *file, 404 const char *display_name, 405 GError **error) 406 { 407 GFile *new_file; 408 char *basename; 409 410 basename = g_locale_from_utf8 (display_name, -1, NULL, NULL, NULL); 411 if (basename == NULL) 412 { 413 g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_FILENAME, 414 _("Invalid filename %s"), display_name); 415 return NULL; 416 } 417 418 new_file = g_file_get_child (file, basename); 419 g_free (basename); 420 421 return new_file; 422 } 423 424 static GFile * 425 g_winhttp_file_set_display_name (GFile *file, 426 const char *display_name, 427 GCancellable *cancellable, 428 GError **error) 429 { 430 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, 431 _("Operation not supported")); 432 433 return NULL; 434 } 435 436 static time_t 437 mktime_utc (SYSTEMTIME *t) 438 { 439 time_t retval; 440 441 static const gint days_before[] = 442 { 443 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 444 }; 445 446 if (t->wMonth < 1 || t->wMonth > 12) 447 return (time_t) -1; 448 449 retval = (t->wYear - 1970) * 365; 450 retval += (t->wYear - 1968) / 4; 451 retval += days_before[t->wMonth-1] + t->wDay - 1; 452 453 if (t->wYear % 4 == 0 && t->wMonth < 3) 454 retval -= 1; 455 456 retval = ((((retval * 24) + t->wHour) * 60) + t->wMinute) * 60 + t->wSecond; 457 458 return retval; 459 } 460 461 static GFileInfo * 462 g_winhttp_file_query_info (GFile *file, 463 const char *attributes, 464 GFileQueryInfoFlags flags, 465 GCancellable *cancellable, 466 GError **error) 467 { 468 GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file); 469 HINTERNET connection, request; 470 const wchar_t *accept_types[] = 471 { 472 L"*/*", 473 NULL, 474 }; 475 GFileInfo *info; 476 GFileAttributeMatcher *matcher; 477 char *basename; 478 wchar_t *content_length; 479 wchar_t *content_type; 480 SYSTEMTIME last_modified; 481 DWORD last_modified_len; 482 483 connection = G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->funcs->pWinHttpConnect 484 (G_WINHTTP_VFS (winhttp_file->vfs)->session, 485 winhttp_file->url.lpszHostName, 486 winhttp_file->url.nPort, 487 0); 488 489 if (connection == NULL) 490 { 491 _g_winhttp_set_error (error, GetLastError (), "HTTP connection"); 492 493 return NULL; 494 } 495 496 request = G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->funcs->pWinHttpOpenRequest 497 (connection, 498 L"HEAD", 499 winhttp_file->url.lpszUrlPath, 500 NULL, 501 WINHTTP_NO_REFERER, 502 accept_types, 503 winhttp_file->url.nScheme == INTERNET_SCHEME_HTTPS ? WINHTTP_FLAG_SECURE : 0); 504 505 if (request == NULL) 506 { 507 _g_winhttp_set_error (error, GetLastError (), "HEAD request"); 508 509 return NULL; 510 } 511 512 if (!G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->funcs->pWinHttpSendRequest 513 (request, 514 NULL, 0, 515 NULL, 0, 516 0, 517 0)) 518 { 519 _g_winhttp_set_error (error, GetLastError (), "HEAD request"); 520 521 return NULL; 522 } 523 524 if (!_g_winhttp_response (winhttp_file->vfs, request, error, "HEAD request")) 525 return NULL; 526 527 matcher = g_file_attribute_matcher_new (attributes); 528 info = g_file_info_new (); 529 g_file_info_set_attribute_mask (info, matcher); 530 531 basename = g_winhttp_file_get_basename (file); 532 g_file_info_set_name (info, basename); 533 g_free (basename); 534 535 content_length = NULL; 536 if (_g_winhttp_query_header (winhttp_file->vfs, 537 request, 538 "HEAD request", 539 WINHTTP_QUERY_CONTENT_LENGTH, 540 &content_length, 541 NULL)) 542 { 543 gint64 cl; 544 int n; 545 546 if (swscanf (content_length, L"%I64d%n", &cl, &n) == 1 && 547 n == wcslen (content_length)) 548 g_file_info_set_size (info, cl); 549 550 g_free (content_length); 551 } 552 553 if (matcher == NULL) 554 return info; 555 556 content_type = NULL; 557 if (_g_winhttp_query_header (winhttp_file->vfs, 558 request, 559 "HEAD request", 560 WINHTTP_QUERY_CONTENT_TYPE, 561 &content_type, 562 NULL)) 563 { 564 char *ct = g_utf16_to_utf8 (content_type, -1, NULL, NULL, NULL); 565 566 if (ct != NULL) 567 { 568 char *p = strchr (ct, ';'); 569 570 if (p != NULL) 571 { 572 char *tmp = g_strndup (ct, p - ct); 573 574 g_file_info_set_content_type (info, tmp); 575 g_free (tmp); 576 } 577 else 578 g_file_info_set_content_type (info, ct); 579 } 580 581 g_free (ct); 582 } 583 584 last_modified_len = sizeof (last_modified); 585 if (G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->funcs->pWinHttpQueryHeaders 586 (request, 587 WINHTTP_QUERY_LAST_MODIFIED | WINHTTP_QUERY_FLAG_SYSTEMTIME, 588 NULL, 589 &last_modified, 590 &last_modified_len, 591 NULL) && 592 last_modified_len == sizeof (last_modified) && 593 /* Don't bother comparing to the exact Y2038 moment */ 594 last_modified.wYear >= 1970 && 595 last_modified.wYear < 2038) 596 { 597 GTimeVal tv; 598 599 tv.tv_sec = mktime_utc (&last_modified); 600 tv.tv_usec = last_modified.wMilliseconds * 1000; 601 602 g_file_info_set_modification_time (info, &tv); 603 } 604 605 g_file_attribute_matcher_unref (matcher); 606 607 return info; 608 } 609 610 static GFileInputStream * 611 g_winhttp_file_read (GFile *file, 612 GCancellable *cancellable, 613 GError **error) 614 { 615 GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file); 616 HINTERNET connection, request; 617 const wchar_t *accept_types[] = 618 { 619 L"*/*", 620 NULL, 621 }; 622 623 connection = G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->funcs->pWinHttpConnect 624 (G_WINHTTP_VFS (winhttp_file->vfs)->session, 625 winhttp_file->url.lpszHostName, 626 winhttp_file->url.nPort, 627 0); 628 629 if (connection == NULL) 630 { 631 _g_winhttp_set_error (error, GetLastError (), "HTTP connection"); 632 633 return NULL; 634 } 635 636 request = G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->funcs->pWinHttpOpenRequest 637 (connection, 638 L"GET", 639 winhttp_file->url.lpszUrlPath, 640 NULL, 641 WINHTTP_NO_REFERER, 642 accept_types, 643 winhttp_file->url.nScheme == INTERNET_SCHEME_HTTPS ? WINHTTP_FLAG_SECURE : 0); 644 645 if (request == NULL) 646 { 647 _g_winhttp_set_error (error, GetLastError (), "GET request"); 648 649 return NULL; 650 } 651 652 return _g_winhttp_file_input_stream_new (winhttp_file, connection, request); 653 } 654 655 static GFileOutputStream * 656 g_winhttp_file_create (GFile *file, 657 GFileCreateFlags flags, 658 GCancellable *cancellable, 659 GError **error) 660 { 661 GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file); 662 HINTERNET connection; 663 664 connection = G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->funcs->pWinHttpConnect 665 (G_WINHTTP_VFS (winhttp_file->vfs)->session, 666 winhttp_file->url.lpszHostName, 667 winhttp_file->url.nPort, 668 0); 669 670 if (connection == NULL) 671 { 672 _g_winhttp_set_error (error, GetLastError (), "HTTP connection"); 673 674 return NULL; 675 } 676 677 return _g_winhttp_file_output_stream_new (winhttp_file, connection); 678 } 679 680 #if 0 681 682 static GFileOutputStream * 683 g_winhttp_file_replace (GFile *file, 684 const char *etag, 685 gboolean make_backup, 686 GFileCreateFlags flags, 687 GCancellable *cancellable, 688 GError **error) 689 { 690 /* FIXME: Implement */ 691 692 return NULL; 693 } 694 695 696 static gboolean 697 g_winhttp_file_delete (GFile *file, 698 GCancellable *cancellable, 699 GError **error) 700 { 701 /* FIXME: Implement */ 702 703 return FALSE; 704 } 705 706 static gboolean 707 g_winhttp_file_make_directory (GFile *file, 708 GCancellable *cancellable, 709 GError **error) 710 { 711 /* FIXME: Implement */ 712 713 return FALSE; 714 } 715 716 static gboolean 717 g_winhttp_file_copy (GFile *source, 718 GFile *destination, 719 GFileCopyFlags flags, 720 GCancellable *cancellable, 721 GFileProgressCallback progress_callback, 722 gpointer progress_callback_data, 723 GError **error) 724 { 725 /* Fall back to default copy?? */ 726 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, 727 "Copy not supported"); 728 729 return FALSE; 730 } 731 732 static gboolean 733 g_winhttp_file_move (GFile *source, 734 GFile *destination, 735 GFileCopyFlags flags, 736 GCancellable *cancellable, 737 GFileProgressCallback progress_callback, 738 gpointer progress_callback_data, 739 GError **error) 740 { 741 /* FIXME: Implement */ 742 743 return FALSE; 744 } 745 746 #endif 747 748 static void 749 g_winhttp_file_file_iface_init (GFileIface *iface) 750 { 751 iface->dup = g_winhttp_file_dup; 752 iface->hash = g_winhttp_file_hash; 753 iface->equal = g_winhttp_file_equal; 754 iface->is_native = g_winhttp_file_is_native; 755 iface->has_uri_scheme = g_winhttp_file_has_uri_scheme; 756 iface->get_uri_scheme = g_winhttp_file_get_uri_scheme; 757 iface->get_basename = g_winhttp_file_get_basename; 758 iface->get_path = g_winhttp_file_get_path; 759 iface->get_uri = g_winhttp_file_get_uri; 760 iface->get_parse_name = g_winhttp_file_get_parse_name; 761 iface->get_parent = g_winhttp_file_get_parent; 762 iface->prefix_matches = g_winhttp_file_prefix_matches; 763 iface->get_relative_path = g_winhttp_file_get_relative_path; 764 iface->resolve_relative_path = g_winhttp_file_resolve_relative_path; 765 iface->get_child_for_display_name = g_winhttp_file_get_child_for_display_name; 766 iface->set_display_name = g_winhttp_file_set_display_name; 767 iface->query_info = g_winhttp_file_query_info; 768 iface->read_fn = g_winhttp_file_read; 769 iface->create = g_winhttp_file_create; 770 #if 0 771 iface->replace = g_winhttp_file_replace; 772 iface->delete_file = g_winhttp_file_delete; 773 iface->make_directory = g_winhttp_file_make_directory; 774 iface->copy = g_winhttp_file_copy; 775 iface->move = g_winhttp_file_move; 776 #endif 777 } 778