/src/glib/gio/glocalvfs.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* GIO - GLib Input, Output and Streaming Library |
2 | | * |
3 | | * Copyright (C) 2006-2007 Red Hat, Inc. |
4 | | * |
5 | | * SPDX-License-Identifier: LGPL-2.1-or-later |
6 | | * |
7 | | * This library is free software; you can redistribute it and/or |
8 | | * modify it under the terms of the GNU Lesser General Public |
9 | | * License as published by the Free Software Foundation; either |
10 | | * version 2.1 of the License, or (at your option) any later version. |
11 | | * |
12 | | * This library is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | | * Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General |
18 | | * Public License along with this library; if not, see <http://www.gnu.org/licenses/>. |
19 | | * |
20 | | * Author: Alexander Larsson <alexl@redhat.com> |
21 | | */ |
22 | | |
23 | | #include "config.h" |
24 | | #include "glocalvfs.h" |
25 | | #include "glocalfile.h" |
26 | | #include "giomodule.h" |
27 | | #include "giomodule-priv.h" |
28 | | #include "gvfs.h" |
29 | | #include <gio/gdummyfile.h> |
30 | | #include <sys/types.h> |
31 | | #ifdef G_OS_UNIX |
32 | | #include "glib-unix.h" |
33 | | #include <pwd.h> |
34 | | #endif |
35 | | #include <string.h> |
36 | | |
37 | | |
38 | | struct _GLocalVfs |
39 | | { |
40 | | GVfs parent; |
41 | | }; |
42 | | |
43 | | struct _GLocalVfsClass |
44 | | { |
45 | | GVfsClass parent_class; |
46 | | |
47 | | }; |
48 | | |
49 | | #define g_local_vfs_get_type _g_local_vfs_get_type |
50 | | G_DEFINE_TYPE_WITH_CODE (GLocalVfs, g_local_vfs, G_TYPE_VFS, |
51 | | _g_io_modules_ensure_extension_points_registered (); |
52 | | g_io_extension_point_implement (G_VFS_EXTENSION_POINT_NAME, |
53 | | g_define_type_id, |
54 | | "local", |
55 | | 0)) |
56 | | static void |
57 | | g_local_vfs_finalize (GObject *object) |
58 | 0 | { |
59 | | /* must chain up */ |
60 | 0 | G_OBJECT_CLASS (g_local_vfs_parent_class)->finalize (object); |
61 | 0 | } |
62 | | |
63 | | static void |
64 | | g_local_vfs_init (GLocalVfs *vfs) |
65 | 0 | { |
66 | 0 | } |
67 | | |
68 | | /** |
69 | | * g_local_vfs_new: |
70 | | * |
71 | | * Returns a new #GVfs handle for a local vfs. |
72 | | * |
73 | | * Returns: a new #GVfs handle. |
74 | | **/ |
75 | | GVfs * |
76 | | _g_local_vfs_new (void) |
77 | 0 | { |
78 | 0 | return g_object_new (G_TYPE_LOCAL_VFS, NULL); |
79 | 0 | } |
80 | | |
81 | | static GFile * |
82 | | g_local_vfs_get_file_for_path (GVfs *vfs, |
83 | | const char *path) |
84 | 0 | { |
85 | 0 | if (*path == '\0') |
86 | 0 | return _g_dummy_file_new (path); |
87 | 0 | else |
88 | 0 | return _g_local_file_new (path); |
89 | 0 | } |
90 | | |
91 | | static GFile * |
92 | | g_local_vfs_get_file_for_uri (GVfs *vfs, |
93 | | const char *uri) |
94 | 0 | { |
95 | 0 | char *path; |
96 | 0 | GFile *file; |
97 | 0 | char *stripped_uri, *hash, *question_mark; |
98 | | |
99 | | /* As per https://url.spec.whatwg.org/#file-state, file: URIs can contain |
100 | | * query and fragment sections. We ignore them in order to get only the file |
101 | | * path. Compliance to this part of the WhatWG spec doesn’t necessarily mean |
102 | | * we comply with the entire spec. */ |
103 | 0 | if (strchr (uri, '#') != NULL) |
104 | 0 | { |
105 | 0 | stripped_uri = g_strdup (uri); |
106 | 0 | hash = strchr (stripped_uri, '#'); |
107 | 0 | *hash = 0; |
108 | 0 | } |
109 | 0 | else if (strchr (uri, '?') != NULL) |
110 | 0 | { |
111 | 0 | stripped_uri = g_strdup (uri); |
112 | 0 | question_mark = strchr (stripped_uri, '?'); |
113 | 0 | *question_mark = 0; |
114 | 0 | } |
115 | 0 | else |
116 | 0 | stripped_uri = (char *)uri; |
117 | | |
118 | 0 | path = g_filename_from_uri (stripped_uri, NULL, NULL); |
119 | |
|
120 | 0 | if (stripped_uri != uri) |
121 | 0 | g_free (stripped_uri); |
122 | | |
123 | 0 | if (path != NULL) |
124 | 0 | file = _g_local_file_new (path); |
125 | 0 | else |
126 | 0 | file = _g_dummy_file_new (uri); |
127 | |
|
128 | 0 | g_free (path); |
129 | |
|
130 | 0 | return file; |
131 | 0 | } |
132 | | |
133 | | static const gchar * const * |
134 | | g_local_vfs_get_supported_uri_schemes (GVfs *vfs) |
135 | 0 | { |
136 | 0 | static const gchar * uri_schemes[] = { "file", NULL }; |
137 | |
|
138 | 0 | return uri_schemes; |
139 | 0 | } |
140 | | |
141 | | static GFile * |
142 | | g_local_vfs_parse_name (GVfs *vfs, |
143 | | const char *parse_name) |
144 | 0 | { |
145 | 0 | GFile *file; |
146 | 0 | char *filename; |
147 | 0 | char *user_prefix; |
148 | 0 | const char *user_end; |
149 | 0 | char *rest; |
150 | | |
151 | 0 | g_return_val_if_fail (G_IS_VFS (vfs), NULL); |
152 | 0 | g_return_val_if_fail (parse_name != NULL, NULL); |
153 | | |
154 | 0 | if (g_ascii_strncasecmp ("file:", parse_name, 5) == 0) |
155 | 0 | filename = g_filename_from_uri (parse_name, NULL, NULL); |
156 | 0 | else |
157 | 0 | { |
158 | 0 | if (*parse_name == '~') |
159 | 0 | { |
160 | 0 | #ifdef G_OS_UNIX |
161 | 0 | const char *user_start; |
162 | 0 | user_start = parse_name + 1; |
163 | 0 | #endif |
164 | 0 | parse_name ++; |
165 | | |
166 | 0 | while (*parse_name != 0 && *parse_name != '/') |
167 | 0 | parse_name++; |
168 | | |
169 | 0 | user_end = parse_name; |
170 | |
|
171 | 0 | #ifdef G_OS_UNIX |
172 | 0 | if (user_end == user_start) |
173 | 0 | user_prefix = g_strdup (g_get_home_dir ()); |
174 | 0 | else |
175 | 0 | { |
176 | 0 | struct passwd *passwd_file_entry; |
177 | 0 | char *user_name; |
178 | |
|
179 | 0 | user_name = g_strndup (user_start, user_end - user_start); |
180 | 0 | passwd_file_entry = g_unix_get_passwd_entry (user_name, NULL); |
181 | 0 | g_free (user_name); |
182 | |
|
183 | 0 | if (passwd_file_entry != NULL && |
184 | 0 | passwd_file_entry->pw_dir != NULL) |
185 | 0 | user_prefix = g_strdup (passwd_file_entry->pw_dir); |
186 | 0 | else |
187 | 0 | user_prefix = g_strdup (g_get_home_dir ()); |
188 | |
|
189 | 0 | g_free (passwd_file_entry); |
190 | 0 | } |
191 | | #else |
192 | | user_prefix = g_strdup (g_get_home_dir ()); |
193 | | #endif |
194 | |
|
195 | 0 | rest = NULL; |
196 | 0 | if (*user_end != 0) |
197 | 0 | rest = g_filename_from_utf8 (user_end, -1, NULL, NULL, NULL); |
198 | | |
199 | 0 | filename = g_build_filename (user_prefix, rest, NULL); |
200 | 0 | g_free (rest); |
201 | 0 | g_free (user_prefix); |
202 | 0 | } |
203 | 0 | else |
204 | 0 | filename = g_filename_from_utf8 (parse_name, -1, NULL, NULL, NULL); |
205 | 0 | } |
206 | | |
207 | 0 | if (filename == NULL) |
208 | 0 | filename = g_strdup (parse_name); |
209 | | |
210 | 0 | file = _g_local_file_new (filename); |
211 | 0 | g_free (filename); |
212 | |
|
213 | 0 | return file; |
214 | 0 | } |
215 | | |
216 | | static gboolean |
217 | | g_local_vfs_is_active (GVfs *vfs) |
218 | 0 | { |
219 | 0 | return TRUE; |
220 | 0 | } |
221 | | |
222 | | static void |
223 | | g_local_vfs_class_init (GLocalVfsClass *class) |
224 | 0 | { |
225 | 0 | GObjectClass *object_class; |
226 | 0 | GVfsClass *vfs_class; |
227 | | |
228 | 0 | object_class = (GObjectClass *) class; |
229 | |
|
230 | 0 | object_class->finalize = g_local_vfs_finalize; |
231 | |
|
232 | 0 | vfs_class = G_VFS_CLASS (class); |
233 | |
|
234 | 0 | vfs_class->is_active = g_local_vfs_is_active; |
235 | 0 | vfs_class->get_file_for_path = g_local_vfs_get_file_for_path; |
236 | 0 | vfs_class->get_file_for_uri = g_local_vfs_get_file_for_uri; |
237 | 0 | vfs_class->get_supported_uri_schemes = g_local_vfs_get_supported_uri_schemes; |
238 | 0 | vfs_class->parse_name = g_local_vfs_parse_name; |
239 | 0 | } |