• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
G_DEFINE_TYPE_WITH_CODE(GWinHttpFile,g_winhttp_file,G_TYPE_OBJECT,G_IMPLEMENT_INTERFACE (G_TYPE_FILE,g_winhttp_file_file_iface_init))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
g_winhttp_file_class_init(GWinHttpFileClass * klass)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
g_winhttp_file_init(GWinHttpFile * winhttp)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 *
_g_winhttp_file_new(GWinHttpVfs * vfs,const char * uri)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
g_winhttp_file_is_native(GFile * file)140 g_winhttp_file_is_native (GFile *file)
141 {
142   return FALSE;
143 }
144 
145 static gboolean
g_winhttp_file_has_uri_scheme(GFile * file,const char * uri_scheme)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 *
g_winhttp_file_get_uri_scheme(GFile * file)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 *
g_winhttp_file_get_basename(GFile * file)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 *
g_winhttp_file_get_display_name(GFile * file)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 *
g_winhttp_file_get_path(GFile * file)197 g_winhttp_file_get_path (GFile *file)
198 {
199   return NULL;
200 }
201 
202 static char *
g_winhttp_file_get_uri(GFile * file)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 *
g_winhttp_file_get_parse_name(GFile * file)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 *
g_winhttp_file_get_parent(GFile * file)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 *
g_winhttp_file_dup(GFile * file)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
g_winhttp_file_hash(GFile * file)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
g_winhttp_file_equal(GFile * file1,GFile * file2)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 *
match_prefix(const char * path,const char * prefix)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
g_winhttp_file_prefix_matches(GFile * parent,GFile * descendant)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 *
g_winhttp_file_get_relative_path(GFile * parent,GFile * descendant)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 *
g_winhttp_file_resolve_relative_path(GFile * file,const char * relative_path)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 *
g_winhttp_file_get_child_for_display_name(GFile * file,const char * display_name,GError ** error)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 *
g_winhttp_file_set_display_name(GFile * file,const char * display_name,GCancellable * cancellable,GError ** error)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 *
g_winhttp_file_query_info(GFile * file,const char * attributes,GFileQueryInfoFlags flags,GCancellable * cancellable,GError ** error)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       int 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 *
g_winhttp_file_read(GFile * file,GCancellable * cancellable,GError ** error)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 *
g_winhttp_file_create(GFile * file,GFileCreateFlags flags,GCancellable * cancellable,GError ** error)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
g_winhttp_file_file_iface_init(GFileIface * iface)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 }
789