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