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