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