Home | History | Annotate | Download | only in win32
      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