1 /* GIO - GLib Input, Output and Streaming Library
2 *
3 * Copyright (C) 2006-2007 Red Hat, Inc.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 *
20 * Author: Alexander Larsson <alexl@redhat.com>
21 */
22
23 #include <config.h>
24
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <sys/un.h>
30
31 #include <glib.h>
32 #include <glib/gi18n.h>
33 #include "gvfsbackend.h"
34 #include "gvfsjobsource.h"
35 #include <gvfsjobopenforread.h>
36 #include <gvfsjobopeniconforread.h>
37 #include <gvfsjobopenforwrite.h>
38 #include <gvfsjobqueryinfo.h>
39 #include <gvfsjobqueryfsinfo.h>
40 #include <gvfsjobsetdisplayname.h>
41 #include <gvfsjobenumerate.h>
42 #include <gvfsjobdelete.h>
43 #include <gvfsjobtrash.h>
44 #include <gvfsjobunmount.h>
45 #include <gvfsjobmountmountable.h>
46 #include <gvfsjobunmountmountable.h>
47 #include <gvfsjobstartmountable.h>
48 #include <gvfsjobstopmountable.h>
49 #include <gvfsjobpollmountable.h>
50 #include <gvfsjobmakedirectory.h>
51 #include <gvfsjobmakesymlink.h>
52 #include <gvfsjobcreatemonitor.h>
53 #include <gvfsjobcopy.h>
54 #include <gvfsjobmove.h>
55 #include <gvfsjobpush.h>
56 #include <gvfsjobpull.h>
57 #include <gvfsjobsetattribute.h>
58 #include <gvfsjobqueryattributes.h>
59 #include <gvfsdbus.h>
60
61 enum {
62 PROP_0,
63 PROP_OBJECT_PATH,
64 PROP_DAEMON
65 };
66
67 struct _GVfsBackendPrivate
68 {
69 GVfsDaemon *daemon;
70 char *object_path;
71
72 gboolean is_mounted;
73 char *display_name;
74 char *stable_name;
75 char **x_content_types;
76 GIcon *icon;
77 GIcon *symbolic_icon;
78 char *prefered_filename_encoding;
79 gboolean user_visible;
80 char *default_location;
81 GMountSpec *mount_spec;
82 gboolean block_requests;
83
84 GSettings *lockdown_settings;
85 gboolean readonly_lockdown;
86 };
87
88
89 /* TODO: Real P_() */
90 #define P_(_x) (_x)
91
92 static void g_vfs_backend_job_source_iface_init (GVfsJobSourceIface *iface);
93 static void g_vfs_backend_get_property (GObject *object,
94 guint prop_id,
95 GValue *value,
96 GParamSpec *pspec);
97 static void g_vfs_backend_set_property (GObject *object,
98 guint prop_id,
99 const GValue *value,
100 GParamSpec *pspec);
101 static GObject* g_vfs_backend_constructor (GType type,
102 guint n_construct_properties,
103 GObjectConstructParam *construct_params);
104
105
106 G_DEFINE_TYPE_WITH_CODE (GVfsBackend, g_vfs_backend, G_TYPE_OBJECT,
107 G_ADD_PRIVATE (GVfsBackend)
108 G_IMPLEMENT_INTERFACE (G_VFS_TYPE_JOB_SOURCE,
109 g_vfs_backend_job_source_iface_init))
110
111
112 static GHashTable *registered_backends = NULL;
113
114 void
g_vfs_register_backend(GType backend_type,const char * type)115 g_vfs_register_backend (GType backend_type,
116 const char *type)
117 {
118 if (registered_backends == NULL)
119 registered_backends = g_hash_table_new_full (g_str_hash, g_str_equal,
120 g_free, NULL);
121
122 g_hash_table_insert (registered_backends,
123 g_strdup (type), (void *)backend_type);
124 }
125
126 GType
g_vfs_lookup_backend(const char * type)127 g_vfs_lookup_backend (const char *type)
128 {
129 gpointer res;
130
131 if (registered_backends != NULL)
132 {
133 res = g_hash_table_lookup (registered_backends, type);
134 if (res != NULL)
135 return (GType)res;
136 }
137
138 return G_TYPE_INVALID;
139 }
140
141 static void
g_vfs_backend_finalize(GObject * object)142 g_vfs_backend_finalize (GObject *object)
143 {
144 GVfsBackend *backend;
145
146 backend = G_VFS_BACKEND (object);
147
148 g_vfs_daemon_unregister_path (backend->priv->daemon, backend->priv->object_path);
149 g_object_unref (backend->priv->daemon);
150 g_free (backend->priv->object_path);
151
152 g_free (backend->priv->display_name);
153 g_free (backend->priv->stable_name);
154 g_strfreev (backend->priv->x_content_types);
155 g_clear_object (&backend->priv->icon);
156 g_clear_object (&backend->priv->symbolic_icon);
157 g_free (backend->priv->prefered_filename_encoding);
158 g_free (backend->priv->default_location);
159 if (backend->priv->mount_spec)
160 g_mount_spec_unref (backend->priv->mount_spec);
161
162 g_clear_object (&backend->priv->lockdown_settings);
163
164 if (G_OBJECT_CLASS (g_vfs_backend_parent_class)->finalize)
165 (*G_OBJECT_CLASS (g_vfs_backend_parent_class)->finalize) (object);
166 }
167
168 static void
g_vfs_backend_job_source_iface_init(GVfsJobSourceIface * iface)169 g_vfs_backend_job_source_iface_init (GVfsJobSourceIface *iface)
170 {
171 }
172
173 static void
g_vfs_backend_class_init(GVfsBackendClass * klass)174 g_vfs_backend_class_init (GVfsBackendClass *klass)
175 {
176 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
177
178 gobject_class->constructor = g_vfs_backend_constructor;
179 gobject_class->finalize = g_vfs_backend_finalize;
180 gobject_class->set_property = g_vfs_backend_set_property;
181 gobject_class->get_property = g_vfs_backend_get_property;
182
183 g_object_class_install_property (gobject_class,
184 PROP_OBJECT_PATH,
185 g_param_spec_string ("object-path",
186 P_("Backend object path"),
187 P_("The dbus object path for the backend object."),
188 "",
189 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
190 G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
191 g_object_class_install_property (gobject_class,
192 PROP_DAEMON,
193 g_param_spec_object ("daemon",
194 P_("Daemon"),
195 P_("The daemon this backend is handled by."),
196 G_VFS_TYPE_DAEMON,
197 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
198 G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
199 }
200
201 static void
g_vfs_backend_init(GVfsBackend * backend)202 g_vfs_backend_init (GVfsBackend *backend)
203 {
204 backend->priv = g_vfs_backend_get_instance_private (backend);
205 backend->priv->icon = NULL;
206 backend->priv->symbolic_icon = NULL;
207 backend->priv->prefered_filename_encoding = g_strdup ("");
208 backend->priv->display_name = g_strdup ("");
209 backend->priv->stable_name = g_strdup ("");
210 backend->priv->user_visible = TRUE;
211 backend->priv->default_location = g_strdup ("");
212 }
213
214 static void
g_vfs_backend_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)215 g_vfs_backend_set_property (GObject *object,
216 guint prop_id,
217 const GValue *value,
218 GParamSpec *pspec)
219 {
220 GVfsBackend *backend = G_VFS_BACKEND (object);
221
222 switch (prop_id)
223 {
224 case PROP_OBJECT_PATH:
225 backend->priv->object_path = g_value_dup_string (value);
226 break;
227 case PROP_DAEMON:
228 backend->priv->daemon = G_VFS_DAEMON (g_value_dup_object (value));
229 break;
230 default:
231 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
232 break;
233 }
234 }
235
236 static void
g_vfs_backend_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)237 g_vfs_backend_get_property (GObject *object,
238 guint prop_id,
239 GValue *value,
240 GParamSpec *pspec)
241 {
242 GVfsBackend *backend = G_VFS_BACKEND (object);
243
244 switch (prop_id)
245 {
246 case PROP_OBJECT_PATH:
247 g_value_set_string (value, backend->priv->object_path);
248 break;
249 case PROP_DAEMON:
250 g_value_set_object (value, backend->priv->daemon);
251 break;
252 default:
253 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
254 break;
255 }
256 }
257
258 static GDBusInterfaceSkeleton *
register_path_cb(GDBusConnection * conn,const char * obj_path,gpointer data)259 register_path_cb (GDBusConnection *conn,
260 const char *obj_path,
261 gpointer data)
262 {
263 GError *error;
264 GVfsDBusMount *skeleton;
265
266 skeleton = gvfs_dbus_mount_skeleton_new ();
267 g_signal_connect (skeleton, "handle-enumerate", G_CALLBACK (g_vfs_job_enumerate_new_handle), data);
268 g_signal_connect (skeleton, "handle-query-info", G_CALLBACK (g_vfs_job_query_info_new_handle), data);
269 g_signal_connect (skeleton, "handle-query-filesystem-info", G_CALLBACK (g_vfs_job_query_fs_info_new_handle), data);
270 g_signal_connect (skeleton, "handle-set-display-name", G_CALLBACK (g_vfs_job_set_display_name_new_handle), data);
271 g_signal_connect (skeleton, "handle-delete", G_CALLBACK (g_vfs_job_delete_new_handle), data);
272 g_signal_connect (skeleton, "handle-trash", G_CALLBACK (g_vfs_job_trash_new_handle), data);
273 g_signal_connect (skeleton, "handle-make-directory", G_CALLBACK (g_vfs_job_make_directory_new_handle), data);
274 g_signal_connect (skeleton, "handle-make-symbolic-link", G_CALLBACK (g_vfs_job_make_symlink_new_handle), data);
275 g_signal_connect (skeleton, "handle-query-settable-attributes", G_CALLBACK (g_vfs_job_query_settable_attributes_new_handle), data);
276 g_signal_connect (skeleton, "handle-query-writable-namespaces", G_CALLBACK (g_vfs_job_query_writable_namespaces_new_handle), data);
277 g_signal_connect (skeleton, "handle-set-attribute", G_CALLBACK (g_vfs_job_set_attribute_new_handle), data);
278 g_signal_connect (skeleton, "handle-poll-mountable", G_CALLBACK (g_vfs_job_poll_mountable_new_handle), data);
279 g_signal_connect (skeleton, "handle-start-mountable", G_CALLBACK (g_vfs_job_start_mountable_new_handle), data);
280 g_signal_connect (skeleton, "handle-stop-mountable", G_CALLBACK (g_vfs_job_stop_mountable_new_handle), data);
281 g_signal_connect (skeleton, "handle-unmount-mountable", G_CALLBACK (g_vfs_job_unmount_mountable_new_handle), data);
282 g_signal_connect (skeleton, "handle-eject-mountable", G_CALLBACK (g_vfs_job_eject_mountable_new_handle), data);
283 g_signal_connect (skeleton, "handle-mount-mountable", G_CALLBACK (g_vfs_job_mount_mountable_new_handle), data);
284 g_signal_connect (skeleton, "handle-unmount", G_CALLBACK (g_vfs_job_unmount_new_handle), data);
285 g_signal_connect (skeleton, "handle-open-for-read", G_CALLBACK (g_vfs_job_open_for_read_new_handle), data);
286 g_signal_connect (skeleton, "handle-open-for-write", G_CALLBACK (g_vfs_job_open_for_write_new_handle), data);
287 g_signal_connect (skeleton, "handle-open-for-write-flags", G_CALLBACK (g_vfs_job_open_for_write_new_handle_with_flags), data);
288 g_signal_connect (skeleton, "handle-copy", G_CALLBACK (g_vfs_job_copy_new_handle), data);
289 g_signal_connect (skeleton, "handle-move", G_CALLBACK (g_vfs_job_move_new_handle), data);
290 g_signal_connect (skeleton, "handle-push", G_CALLBACK (g_vfs_job_push_new_handle), data);
291 g_signal_connect (skeleton, "handle-pull", G_CALLBACK (g_vfs_job_pull_new_handle), data);
292 g_signal_connect (skeleton, "handle-create-directory-monitor", G_CALLBACK (g_vfs_job_create_directory_monitor_new_handle), data);
293 g_signal_connect (skeleton, "handle-create-file-monitor", G_CALLBACK (g_vfs_job_create_file_monitor_new_handle), data);
294 g_signal_connect (skeleton, "handle-open-icon-for-read", G_CALLBACK (g_vfs_job_open_icon_for_read_new_handle), data);
295
296 error = NULL;
297 if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (skeleton),
298 conn,
299 obj_path,
300 &error))
301 {
302 g_warning ("Error registering path: %s (%s, %d)\n",
303 error->message, g_quark_to_string (error->domain), error->code);
304 g_error_free (error);
305 }
306
307 return G_DBUS_INTERFACE_SKELETON (skeleton);
308 }
309
310 static GObject*
g_vfs_backend_constructor(GType type,guint n_construct_properties,GObjectConstructParam * construct_params)311 g_vfs_backend_constructor (GType type,
312 guint n_construct_properties,
313 GObjectConstructParam *construct_params)
314 {
315 GObject *object;
316 GVfsBackend *backend;
317
318 object = (* G_OBJECT_CLASS (g_vfs_backend_parent_class)->constructor) (type,
319 n_construct_properties,
320 construct_params);
321 backend = G_VFS_BACKEND (object);
322
323 g_vfs_daemon_register_path (backend->priv->daemon,
324 backend->priv->object_path,
325 register_path_cb,
326 backend);
327
328 return object;
329 }
330
331 GVfsDaemon *
g_vfs_backend_get_daemon(GVfsBackend * backend)332 g_vfs_backend_get_daemon (GVfsBackend *backend)
333 {
334 return backend->priv->daemon;
335 }
336
337 gboolean
g_vfs_backend_is_mounted(GVfsBackend * backend)338 g_vfs_backend_is_mounted (GVfsBackend *backend)
339 {
340 return backend->priv->is_mounted;
341 }
342
343 void
g_vfs_backend_set_display_name(GVfsBackend * backend,const char * display_name)344 g_vfs_backend_set_display_name (GVfsBackend *backend,
345 const char *display_name)
346 {
347 g_free (backend->priv->display_name);
348 backend->priv->display_name = g_strdup (display_name);
349 }
350
351 /**
352 * g_vfs_backend_set_stable_name:
353 * @backend: backend
354 * @stable_name: the stable name
355 *
356 * For filesystems that can change the name during the lifetime
357 * of the filesystem this can be uses to set a separate stable
358 * name. This is used for instance as the directory representing
359 * the mounted file system in the standard UNIX file system
360 * namespace.
361 *
362 * If this function isn't called, the value passed to
363 * g_vfs_backend_set_display_name() will be used instead.
364 **/
365 void
g_vfs_backend_set_stable_name(GVfsBackend * backend,const char * stable_name)366 g_vfs_backend_set_stable_name (GVfsBackend *backend,
367 const char *stable_name)
368 {
369 g_free (backend->priv->stable_name);
370 backend->priv->stable_name = g_strdup (stable_name);
371 }
372
373 /**
374 * g_vfs_backend_set_x_content_types:
375 * @backend: backend
376 * @x_content_types: the x-content types
377 *
378 * For backends where the x-content type is known ahead of time and
379 * won't change (such as a CDDA audio disc backend), this function
380 * should be called when the backend is constructed with the given
381 * types.
382 *
383 * See the <ulink url="http://www.freedesktop.org/wiki/Specifications/shared-mime-info-spec">shared-mime-info</ulink>
384 * specification for more on x-content types.
385 **/
386 void
g_vfs_backend_set_x_content_types(GVfsBackend * backend,char ** x_content_types)387 g_vfs_backend_set_x_content_types (GVfsBackend *backend,
388 char **x_content_types)
389 {
390 g_strfreev (backend->priv->x_content_types);
391 backend->priv->x_content_types = g_strdupv (x_content_types);
392 }
393
394 void
g_vfs_backend_set_icon_name(GVfsBackend * backend,const char * icon_name)395 g_vfs_backend_set_icon_name (GVfsBackend *backend,
396 const char *icon_name)
397 {
398 g_clear_object (&backend->priv->icon);
399 backend->priv->icon = g_themed_icon_new_with_default_fallbacks (icon_name);
400 }
401
402 void
g_vfs_backend_set_icon(GVfsBackend * backend,GIcon * icon)403 g_vfs_backend_set_icon (GVfsBackend *backend,
404 GIcon *icon)
405 {
406 g_clear_object (&backend->priv->icon);
407 backend->priv->icon = g_object_ref (icon);
408 }
409
410 void
g_vfs_backend_set_symbolic_icon_name(GVfsBackend * backend,const char * icon_name)411 g_vfs_backend_set_symbolic_icon_name (GVfsBackend *backend,
412 const char *icon_name)
413 {
414 g_clear_object (&backend->priv->symbolic_icon);
415 backend->priv->symbolic_icon = g_themed_icon_new_with_default_fallbacks (icon_name);
416 }
417
418 void
g_vfs_backend_set_symbolic_icon(GVfsBackend * backend,GIcon * icon)419 g_vfs_backend_set_symbolic_icon (GVfsBackend *backend,
420 GIcon *icon)
421 {
422 g_clear_object (&backend->priv->symbolic_icon);
423 backend->priv->symbolic_icon = g_object_ref (icon);
424 }
425
426 void
g_vfs_backend_set_prefered_filename_encoding(GVfsBackend * backend,const char * prefered_filename_encoding)427 g_vfs_backend_set_prefered_filename_encoding (GVfsBackend *backend,
428 const char *prefered_filename_encoding)
429 {
430 g_free (backend->priv->prefered_filename_encoding);
431 backend->priv->prefered_filename_encoding = g_strdup (prefered_filename_encoding);
432 }
433
434 void
g_vfs_backend_set_user_visible(GVfsBackend * backend,gboolean user_visible)435 g_vfs_backend_set_user_visible (GVfsBackend *backend,
436 gboolean user_visible)
437 {
438 backend->priv->user_visible = user_visible;
439 }
440
441 /**
442 * g_vfs_backend_set_default_location:
443 * @backend: backend
444 * @location: the default location
445 *
446 * With this function the backend can set a "default location", which is a path
447 * that reflects the main entry point for the user (e.g. * the home directory,
448 * or the root of the volume).
449 *
450 * NB: Does not include the mount prefix, you need to prepend that if there is
451 * one.
452 **/
453 void
g_vfs_backend_set_default_location(GVfsBackend * backend,const char * location)454 g_vfs_backend_set_default_location (GVfsBackend *backend,
455 const char *location)
456 {
457 g_free (backend->priv->default_location);
458 backend->priv->default_location = g_strdup (location);
459 }
460
461 void
g_vfs_backend_set_mount_spec(GVfsBackend * backend,GMountSpec * mount_spec)462 g_vfs_backend_set_mount_spec (GVfsBackend *backend,
463 GMountSpec *mount_spec)
464 {
465 if (backend->priv->mount_spec)
466 g_mount_spec_unref (backend->priv->mount_spec);
467 backend->priv->mount_spec = g_mount_spec_ref (mount_spec);
468 }
469
470 const char *
g_vfs_backend_get_backend_type(GVfsBackend * backend)471 g_vfs_backend_get_backend_type (GVfsBackend *backend)
472 {
473 if (backend->priv->mount_spec)
474 return g_mount_spec_get_type (backend->priv->mount_spec);
475 return NULL;
476 }
477
478 const char *
g_vfs_backend_get_display_name(GVfsBackend * backend)479 g_vfs_backend_get_display_name (GVfsBackend *backend)
480 {
481 return backend->priv->display_name;
482 }
483
484 const char *
g_vfs_backend_get_stable_name(GVfsBackend * backend)485 g_vfs_backend_get_stable_name (GVfsBackend *backend)
486 {
487 return backend->priv->stable_name;
488 }
489
490 char **
g_vfs_backend_get_x_content_types(GVfsBackend * backend)491 g_vfs_backend_get_x_content_types (GVfsBackend *backend)
492 {
493 return backend->priv->x_content_types;
494 }
495
496 GIcon *
g_vfs_backend_get_icon(GVfsBackend * backend)497 g_vfs_backend_get_icon (GVfsBackend *backend)
498 {
499 return backend->priv->icon;
500 }
501
502 GIcon *
g_vfs_backend_get_symbolic_icon(GVfsBackend * backend)503 g_vfs_backend_get_symbolic_icon (GVfsBackend *backend)
504 {
505 return backend->priv->symbolic_icon;
506 }
507
508 const char *
g_vfs_backend_get_default_location(GVfsBackend * backend)509 g_vfs_backend_get_default_location (GVfsBackend *backend)
510 {
511 return backend->priv->default_location;
512 }
513
514 GMountSpec *
g_vfs_backend_get_mount_spec(GVfsBackend * backend)515 g_vfs_backend_get_mount_spec (GVfsBackend *backend)
516 {
517 return backend->priv->mount_spec;
518 }
519
520 static void
get_thumbnail_attributes(const char * uri,GFileInfo * info)521 get_thumbnail_attributes (const char *uri,
522 GFileInfo *info)
523 {
524 GChecksum *checksum;
525 char *filename;
526 char *basename;
527
528 checksum = g_checksum_new (G_CHECKSUM_MD5);
529 g_checksum_update (checksum, (const guchar *) uri, strlen (uri));
530
531 basename = g_strconcat (g_checksum_get_string (checksum), ".png", NULL);
532 g_checksum_free (checksum);
533
534 filename = g_build_filename (g_get_user_cache_dir (),
535 "thumbnails", "large", basename,
536 NULL);
537
538 if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
539 g_file_info_set_attribute_byte_string (info, G_FILE_ATTRIBUTE_THUMBNAIL_PATH, filename);
540 else
541 {
542 g_free (filename);
543 filename = g_build_filename (g_get_user_cache_dir (),
544 "thumbnails", "normal", basename,
545 NULL);
546
547 if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
548 g_file_info_set_attribute_byte_string (info, G_FILE_ATTRIBUTE_THUMBNAIL_PATH, filename);
549 else
550 {
551 g_free (filename);
552 filename = g_build_filename (g_get_user_cache_dir (),
553 "thumbnails", "fail",
554 "gnome-thumbnail-factory",
555 basename,
556 NULL);
557
558 if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
559 g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_THUMBNAILING_FAILED, TRUE);
560 }
561 }
562 g_free (basename);
563 g_free (filename);
564 }
565
566 void
g_vfs_backend_add_auto_info(GVfsBackend * backend,GFileAttributeMatcher * matcher,GFileInfo * info,const char * uri)567 g_vfs_backend_add_auto_info (GVfsBackend *backend,
568 GFileAttributeMatcher *matcher,
569 GFileInfo *info,
570 const char *uri)
571 {
572 GMountSpec *spec;
573 char *id;
574
575 if (g_file_attribute_matcher_matches (matcher,
576 G_FILE_ATTRIBUTE_ID_FILESYSTEM))
577 {
578 spec = g_vfs_backend_get_mount_spec (backend);
579 if (spec)
580 {
581 id = g_mount_spec_to_string (spec);
582 g_file_info_set_attribute_string (info,
583 G_FILE_ATTRIBUTE_ID_FILESYSTEM,
584 id);
585 g_free (id);
586 }
587 }
588
589 if (uri != NULL &&
590 (g_file_attribute_matcher_matches (matcher,
591 G_FILE_ATTRIBUTE_THUMBNAIL_PATH) ||
592 g_file_attribute_matcher_matches (matcher,
593 G_FILE_ATTRIBUTE_THUMBNAILING_FAILED)))
594 get_thumbnail_attributes (uri, info);
595
596 if (backend->priv->readonly_lockdown)
597 {
598 g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE, FALSE);
599 g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME, FALSE);
600 g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH, FALSE);
601 g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE, FALSE);
602 }
603 }
604
605 void
g_vfs_backend_add_auto_fs_info(GVfsBackend * backend,GFileAttributeMatcher * matcher,GFileInfo * info)606 g_vfs_backend_add_auto_fs_info (GVfsBackend *backend,
607 GFileAttributeMatcher *matcher,
608 GFileInfo *info)
609 {
610 const char *type;
611
612 type = g_vfs_backend_get_backend_type (backend);
613 if (type)
614 g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_GVFS_BACKEND, type);
615
616 if (backend->priv->readonly_lockdown)
617 g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY, TRUE);
618 }
619
620 void
g_vfs_backend_set_block_requests(GVfsBackend * backend,gboolean value)621 g_vfs_backend_set_block_requests (GVfsBackend *backend, gboolean value)
622 {
623 backend->priv->block_requests = value;
624 }
625
626 gboolean
g_vfs_backend_get_block_requests(GVfsBackend * backend)627 g_vfs_backend_get_block_requests (GVfsBackend *backend)
628 {
629 return backend->priv->block_requests;
630 }
631
632 gboolean
g_vfs_backend_invocation_first_handler(GVfsDBusMount * object,GDBusMethodInvocation * invocation,GVfsBackend * backend)633 g_vfs_backend_invocation_first_handler (GVfsDBusMount *object,
634 GDBusMethodInvocation *invocation,
635 GVfsBackend *backend)
636 {
637 GDBusConnection *connection;
638 GCredentials *credentials;
639 pid_t pid = -1;
640
641 connection = g_dbus_method_invocation_get_connection (invocation);
642 credentials = g_dbus_connection_get_peer_credentials (connection);
643 if (credentials)
644 pid = g_credentials_get_unix_pid (credentials, NULL);
645
646 g_debug ("backend_dbus_handler %s:%s (pid=%ld)\n",
647 g_dbus_method_invocation_get_interface_name (invocation),
648 g_dbus_method_invocation_get_method_name (invocation),
649 (long)pid);
650
651 if (backend->priv->block_requests)
652 {
653 g_dbus_method_invocation_return_error (invocation,
654 G_IO_ERROR,
655 G_IO_ERROR_NOT_MOUNTED,
656 "%s", "Backend currently unmounting");
657 return TRUE;
658 }
659
660 return FALSE;
661 }
662
663 static void
create_mount_tracker_proxy(GTask * task,GAsyncReadyCallback callback)664 create_mount_tracker_proxy (GTask *task,
665 GAsyncReadyCallback callback)
666 {
667 gvfs_dbus_mount_tracker_proxy_new_for_bus (G_BUS_TYPE_SESSION,
668 G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS | G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
669 G_VFS_DBUS_DAEMON_NAME,
670 G_VFS_DBUS_MOUNTTRACKER_PATH,
671 NULL,
672 callback,
673 task);
674 }
675
676 static void
register_mount_cb(GVfsDBusMountTracker * proxy,GAsyncResult * res,gpointer user_data)677 register_mount_cb (GVfsDBusMountTracker *proxy,
678 GAsyncResult *res,
679 gpointer user_data)
680 {
681 GTask *task = G_TASK (user_data);
682 GError *error = NULL;
683
684 if (!gvfs_dbus_mount_tracker_call_register_mount_finish (proxy, res, &error))
685 {
686 g_dbus_error_strip_remote_error (error);
687 g_task_return_error (task, error);
688 }
689 else
690 {
691 g_task_return_boolean (task, TRUE);
692 }
693
694 g_object_unref (task);
695 }
696
697 static void
register_mount_got_proxy_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)698 register_mount_got_proxy_cb (GObject *source_object,
699 GAsyncResult *res,
700 gpointer user_data)
701 {
702 GTask *task = G_TASK (user_data);
703 GVfsDBusMountTracker *proxy;
704 GError *error = NULL;
705 GVfsBackend *backend = G_VFS_BACKEND (g_task_get_source_object (task));
706 char *stable_name;
707 char *x_content_types_string;
708 char *icon_str;
709 char *symbolic_icon_str;
710
711 proxy = gvfs_dbus_mount_tracker_proxy_new_for_bus_finish (res, &error);
712 if (proxy == NULL)
713 {
714 g_dbus_error_strip_remote_error (error);
715 g_task_return_error (task, error);
716 g_object_unref (task);
717 return;
718 }
719
720 backend->priv->is_mounted = TRUE;
721
722 if (backend->priv->x_content_types != NULL && g_strv_length (backend->priv->x_content_types) > 0)
723 x_content_types_string = g_strjoinv (" ", backend->priv->x_content_types);
724 else
725 x_content_types_string = g_strdup ("");
726
727 if (backend->priv->icon != NULL)
728 icon_str = g_icon_to_string (backend->priv->icon);
729 else
730 icon_str = g_strdup ("");
731
732 if (backend->priv->symbolic_icon != NULL)
733 symbolic_icon_str = g_icon_to_string (backend->priv->symbolic_icon);
734 else
735 symbolic_icon_str = g_strdup ("");
736
737 stable_name = g_mount_spec_to_string (backend->priv->mount_spec);
738
739 gvfs_dbus_mount_tracker_call_register_mount (proxy,
740 backend->priv->object_path,
741 backend->priv->display_name,
742 stable_name,
743 x_content_types_string,
744 icon_str,
745 symbolic_icon_str,
746 backend->priv->prefered_filename_encoding,
747 backend->priv->user_visible,
748 g_mount_spec_to_dbus (backend->priv->mount_spec),
749 backend->priv->default_location ? backend->priv->default_location : "",
750 NULL,
751 (GAsyncReadyCallback) register_mount_cb,
752 task);
753
754 g_free (stable_name);
755 g_free (x_content_types_string);
756 g_free (icon_str);
757 g_free (symbolic_icon_str);
758 g_object_unref (proxy);
759 }
760
761 void
g_vfs_backend_register_mount(GVfsBackend * backend,GAsyncReadyCallback callback,gpointer user_data)762 g_vfs_backend_register_mount (GVfsBackend *backend,
763 GAsyncReadyCallback callback,
764 gpointer user_data)
765 {
766 GTask *task;
767
768 task = g_task_new (backend, NULL, callback, user_data);
769 g_task_set_source_tag (task, g_vfs_backend_register_mount);
770
771 create_mount_tracker_proxy (task, register_mount_got_proxy_cb);
772 }
773
774 gboolean
g_vfs_backend_register_mount_finish(GVfsBackend * backend,GAsyncResult * res,GError ** error)775 g_vfs_backend_register_mount_finish (GVfsBackend *backend,
776 GAsyncResult *res,
777 GError **error)
778 {
779 g_return_val_if_fail (g_task_is_valid (res, backend), FALSE);
780 g_return_val_if_fail (g_async_result_is_tagged (res, g_vfs_backend_register_mount), FALSE);
781
782 return g_task_propagate_boolean (G_TASK (res), error);
783 }
784
785 static void
unregister_mount_cb(GVfsDBusMountTracker * proxy,GAsyncResult * res,gpointer user_data)786 unregister_mount_cb (GVfsDBusMountTracker *proxy,
787 GAsyncResult *res,
788 gpointer user_data)
789 {
790 GTask *task = G_TASK (user_data);
791 GError *error = NULL;
792
793 if (!gvfs_dbus_mount_tracker_call_unregister_mount_finish (proxy, res, &error))
794 {
795 g_dbus_error_strip_remote_error (error);
796 g_task_return_error (task, error);
797 }
798 else
799 {
800 g_task_return_boolean (task, TRUE);
801 }
802
803 g_object_unref (task);
804 }
805
806 static void
unregister_mount_got_proxy_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)807 unregister_mount_got_proxy_cb (GObject *source_object,
808 GAsyncResult *res,
809 gpointer user_data)
810 {
811 GTask *task = G_TASK (user_data);
812 GVfsDBusMountTracker *proxy;
813 GError *error = NULL;
814 GVfsBackend *backend = G_VFS_BACKEND (g_task_get_source_object (task));
815
816 proxy = gvfs_dbus_mount_tracker_proxy_new_for_bus_finish (res, &error);
817 if (proxy == NULL)
818 {
819 g_dbus_error_strip_remote_error (error);
820 g_task_return_error (task, error);
821 g_object_unref (task);
822 return;
823 }
824
825 gvfs_dbus_mount_tracker_call_unregister_mount (proxy,
826 backend->priv->object_path,
827 NULL,
828 (GAsyncReadyCallback) unregister_mount_cb,
829 task);
830
831 g_object_unref (proxy);
832 }
833
834 void
g_vfs_backend_unregister_mount(GVfsBackend * backend,GAsyncReadyCallback callback,gpointer user_data)835 g_vfs_backend_unregister_mount (GVfsBackend *backend,
836 GAsyncReadyCallback callback,
837 gpointer user_data)
838 {
839 GTask *task;
840
841 task = g_task_new (backend, NULL, callback, user_data);
842 g_task_set_source_tag (task, g_vfs_backend_unregister_mount);
843
844 create_mount_tracker_proxy (task, unregister_mount_got_proxy_cb);
845 }
846
847 gboolean
g_vfs_backend_unregister_mount_finish(GVfsBackend * backend,GAsyncResult * res,GError ** error)848 g_vfs_backend_unregister_mount_finish (GVfsBackend *backend,
849 GAsyncResult *res,
850 GError **error)
851 {
852 g_return_val_if_fail (g_task_is_valid (res, backend), FALSE);
853 g_return_val_if_fail (g_async_result_is_tagged (res, g_vfs_backend_unregister_mount), FALSE);
854
855 return g_task_propagate_boolean (G_TASK (res), error);
856 }
857
858 /* ------------------------------------------------------------------------------------------------- */
859
860 typedef struct
861 {
862 GMountSource *mount_source;
863
864 const gchar *message;
865 const gchar *choices[3];
866
867 gboolean no_more_processes;
868
869 guint timeout_id;
870 } UnmountWithOpData;
871
872 static void
on_show_processes_reply(GMountSource * mount_source,GAsyncResult * res,gpointer user_data)873 on_show_processes_reply (GMountSource *mount_source,
874 GAsyncResult *res,
875 gpointer user_data)
876 {
877 GTask *task = G_TASK (user_data);
878 UnmountWithOpData *data = g_task_get_task_data (task);
879 gboolean ret, aborted;
880 gint choice;
881
882 if (data->timeout_id != 0)
883 g_source_remove (data->timeout_id);
884
885 ret = g_mount_source_show_processes_finish (mount_source, res, &aborted, &choice);
886 if (!data->no_more_processes && !ret)
887 {
888 /* If the "show-processes" signal wasn't handled */
889 g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_BUSY,
890 _("File system is busy"));
891 }
892 else if (!data->no_more_processes && (aborted || choice == 1))
893 {
894 g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED_HANDLED,
895 "GMountOperation aborted");
896 }
897 else
898 {
899 g_task_return_boolean (task, TRUE);
900 }
901
902 g_object_unref (task);
903 }
904
905 static gboolean
on_update_processes_timeout(gpointer user_data)906 on_update_processes_timeout (gpointer user_data)
907 {
908 GTask *task = G_TASK (user_data);
909 UnmountWithOpData *data = g_task_get_task_data (task);
910 GArray *processes;
911 GVfsBackend *backend = G_VFS_BACKEND (g_task_get_source_object (task));
912 GVfsDaemon *daemon = g_vfs_backend_get_daemon (backend);
913
914 if (!g_vfs_daemon_has_blocking_processes (daemon))
915 {
916 g_mount_source_abort (data->mount_source);
917 data->timeout_id = 0;
918 data->no_more_processes = TRUE;
919
920 return G_SOURCE_REMOVE;
921 }
922 else
923 {
924 processes = g_vfs_daemon_get_blocking_processes (daemon);
925 g_mount_source_show_processes_async (data->mount_source,
926 data->message,
927 processes,
928 data->choices,
929 (GAsyncReadyCallback) on_show_processes_reply,
930 task);
931 g_array_unref (processes);
932
933 return G_SOURCE_CONTINUE;
934 }
935 }
936
937 static void
unmount_with_op_data_free(UnmountWithOpData * data)938 unmount_with_op_data_free (UnmountWithOpData *data)
939 {
940 g_free (data);
941 }
942
943
944 /**
945 * g_vfs_backend_unmount_with_operation_finish:
946 * @backend: A #GVfsBackend.
947 * @res: A #GAsyncResult obtained from the @callback function passed
948 * to g_vfs_backend_unmount_with_operation().
949 * @error: A #GError, or NULL.
950 *
951 * Gets the result of the operation started by
952 * gvfs_backend_unmount_with_operation_sync().
953 *
954 * If the operation was cancelled, G_IO_ERROR_FAILED_HANDLED will be returned.
955 * If the operation wasn't interacted and there were outstanding jobs,
956 * G_IO_ERROR_BUSY will be returned.
957 *
958 * Returns: %TRUE if the backend should be unmounted (either no blocking
959 * processes or the user decided to unmount anyway), %FALSE if
960 * no action should be taken (error is set).
961 */
962 gboolean
g_vfs_backend_unmount_with_operation_finish(GVfsBackend * backend,GAsyncResult * res,GError ** error)963 g_vfs_backend_unmount_with_operation_finish (GVfsBackend *backend,
964 GAsyncResult *res,
965 GError **error)
966 {
967 g_return_val_if_fail (g_task_is_valid (res, backend), FALSE);
968 g_return_val_if_fail (g_async_result_is_tagged (res, g_vfs_backend_unmount_with_operation), FALSE);
969
970 return g_task_propagate_boolean (G_TASK (res), error);
971 }
972
973 /**
974 * gvfs_backend_unmount_with_operation:
975 * @backend: A #GVfsBackend.
976 * @callback: A #GAsyncReadyCallback.
977 * @user_data: User data to pass to @callback.
978 *
979 * Utility function to checks if there are pending operations on
980 * @backend preventing unmount. If not, then @callback is invoked
981 * immediately.
982 *
983 * Otherwise, a dialog will be shown (using @mount_source) to interact
984 * with the user about blocking processes (e.g. using the
985 * #GMountOperation::show-processes signal). The list of blocking
986 * processes is continuously updated.
987 *
988 * Once the user has decided (or if it's not possible to interact with
989 * the user), @callback will be invoked. You can then call
990 * g_vfs_backend_unmount_with_operation_finish() to get the result
991 * of the operation.
992 */
993 void
g_vfs_backend_unmount_with_operation(GVfsBackend * backend,GMountSource * mount_source,GAsyncReadyCallback callback,gpointer user_data)994 g_vfs_backend_unmount_with_operation (GVfsBackend *backend,
995 GMountSource *mount_source,
996 GAsyncReadyCallback callback,
997 gpointer user_data)
998 {
999 GArray *processes;
1000 UnmountWithOpData *data;
1001 GVfsDaemon *daemon;
1002 GTask *task;
1003
1004 g_return_if_fail (G_VFS_IS_BACKEND (backend));
1005 g_return_if_fail (G_IS_MOUNT_SOURCE (mount_source));
1006 g_return_if_fail (callback != NULL);
1007
1008 task = g_task_new (backend, NULL, callback, user_data);
1009 g_task_set_source_tag (task, g_vfs_backend_unmount_with_operation);
1010
1011 daemon = g_vfs_backend_get_daemon (backend);
1012
1013 /* if no processes are blocking, complete immediately */
1014 if (!g_vfs_daemon_has_blocking_processes (daemon))
1015 {
1016 g_task_return_boolean (task, TRUE);
1017 g_object_unref (task);
1018 return;
1019 }
1020
1021 data = g_new0 (UnmountWithOpData, 1);
1022 data->mount_source = mount_source;
1023
1024 data->choices[0] = _("Unmount Anyway");
1025 data->choices[1] = _("Cancel");
1026 data->choices[2] = NULL;
1027 data->message = _("Volume is busy\n"
1028 "One or more applications are keeping the volume busy.");
1029
1030 g_task_set_task_data (task, data, (GDestroyNotify) unmount_with_op_data_free);
1031
1032 /* show processes */
1033 processes = g_vfs_daemon_get_blocking_processes (daemon);
1034 g_mount_source_show_processes_async (mount_source,
1035 data->message,
1036 processes,
1037 data->choices,
1038 (GAsyncReadyCallback) on_show_processes_reply,
1039 task);
1040 g_array_unref (processes);
1041
1042 /* update these processes every two secs */
1043 data->timeout_id = g_timeout_add_seconds (2, on_update_processes_timeout, task);
1044 }
1045
1046 static void
forced_unregister_mount_callback(GVfsBackend * backend,GAsyncResult * res,gpointer user_data)1047 forced_unregister_mount_callback (GVfsBackend *backend,
1048 GAsyncResult *res,
1049 gpointer user_data)
1050 {
1051 GVfsDaemon *daemon;
1052 GError *error = NULL;
1053
1054 g_debug ("forced_unregister_mount_callback\n");
1055 if (!g_vfs_backend_unregister_mount_finish (backend, res, &error))
1056 {
1057 g_dbus_error_strip_remote_error (error);
1058 g_warning ("Error unregistering mount: %s (%s, %d)\n",
1059 error->message, g_quark_to_string (error->domain), error->code);
1060 g_error_free (error);
1061 }
1062
1063 /* Unlink job source from daemon */
1064 daemon = g_vfs_backend_get_daemon (backend);
1065 g_vfs_daemon_close_active_channels (daemon, backend);
1066 g_vfs_job_source_closed (G_VFS_JOB_SOURCE (backend));
1067 }
1068
1069 void
g_vfs_backend_force_unmount(GVfsBackend * backend)1070 g_vfs_backend_force_unmount (GVfsBackend *backend)
1071 {
1072 g_vfs_backend_set_block_requests (backend, TRUE);
1073 g_vfs_backend_unregister_mount (backend,
1074 (GAsyncReadyCallback) forced_unregister_mount_callback,
1075 NULL);
1076 }
1077
1078 static void
lockdown_settings_changed(GSettings * settings,gchar * key,gpointer user_data)1079 lockdown_settings_changed (GSettings *settings,
1080 gchar *key,
1081 gpointer user_data)
1082 {
1083 GVfsBackend *backend = G_VFS_BACKEND (user_data);
1084
1085 backend->priv->readonly_lockdown = g_settings_get_boolean (settings,
1086 "mount-removable-storage-devices-as-read-only");
1087 }
1088
1089
1090 void
g_vfs_backend_handle_readonly_lockdown(GVfsBackend * backend)1091 g_vfs_backend_handle_readonly_lockdown (GVfsBackend *backend)
1092 {
1093 backend->priv->lockdown_settings = g_settings_new ("org.gnome.desktop.lockdown");
1094 backend->priv->readonly_lockdown = g_settings_get_boolean (backend->priv->lockdown_settings,
1095 "mount-removable-storage-devices-as-read-only");
1096 g_signal_connect_object (backend->priv->lockdown_settings,
1097 "changed",
1098 G_CALLBACK (lockdown_settings_changed),
1099 backend,
1100 0);
1101 }
1102
1103 gboolean
g_vfs_backend_get_readonly_lockdown(GVfsBackend * backend)1104 g_vfs_backend_get_readonly_lockdown (GVfsBackend *backend)
1105 {
1106 return backend->priv->readonly_lockdown;
1107 }
1108