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