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