• 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 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@redhat.com>
22  * Author: Tor Lillqvist <tml@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
G_DEFINE_TYPE_WITH_CODE(GWinHttpFile,g_winhttp_file,G_TYPE_OBJECT,G_IMPLEMENT_INTERFACE (G_TYPE_FILE,g_winhttp_file_file_iface_init))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
g_winhttp_file_class_init(GWinHttpFileClass * klass)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
g_winhttp_file_init(GWinHttpFile * winhttp)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 *
_g_winhttp_file_new(GWinHttpVfs * vfs,const char * uri)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
g_winhttp_file_is_native(GFile * file)143 g_winhttp_file_is_native (GFile *file)
144 {
145   return FALSE;
146 }
147 
148 static gboolean
g_winhttp_file_has_uri_scheme(GFile * file,const char * uri_scheme)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 *
g_winhttp_file_get_uri_scheme(GFile * file)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 *
g_winhttp_file_get_basename(GFile * file)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 *
g_winhttp_file_get_path(GFile * file)185 g_winhttp_file_get_path (GFile *file)
186 {
187   return NULL;
188 }
189 
190 static char *
g_winhttp_file_get_uri(GFile * file)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 *
g_winhttp_file_get_parse_name(GFile * file)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 *
g_winhttp_file_get_parent(GFile * file)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 *
g_winhttp_file_dup(GFile * file)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
g_winhttp_file_hash(GFile * file)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
g_winhttp_file_equal(GFile * file1,GFile * file2)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 *
match_prefix(const char * path,const char * prefix)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
g_winhttp_file_prefix_matches(GFile * parent,GFile * descendant)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 *
g_winhttp_file_get_relative_path(GFile * parent,GFile * descendant)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 *
g_winhttp_file_resolve_relative_path(GFile * file,const char * relative_path)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 *
g_winhttp_file_get_child_for_display_name(GFile * file,const char * display_name,GError ** error)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 *
g_winhttp_file_set_display_name(GFile * file,const char * display_name,GCancellable * cancellable,GError ** error)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
mktime_utc(SYSTEMTIME * 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 *
g_winhttp_file_query_info(GFile * file,const char * attributes,GFileQueryInfoFlags flags,GCancellable * cancellable,GError ** error)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 *
g_winhttp_file_read(GFile * file,GCancellable * cancellable,GError ** error)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 *
g_winhttp_file_create(GFile * file,GFileCreateFlags flags,GCancellable * cancellable,GError ** error)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
g_winhttp_file_file_iface_init(GFileIface * iface)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