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 * Authors: Alexander Larsson <alexl@redhat.com>
21 * Cosimo Cecchi <cosimoc@gnome.org>
22 */
23
24 #include <config.h>
25
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <sys/wait.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include <string.h>
33
34 #include <glib.h>
35 #include <glib/gstdio.h>
36 #include <glib/gi18n.h>
37 #include <gio/gio.h>
38 #include <gio/gunixmounts.h>
39
40 #include "gvfsbackendcomputer.h"
41 #include "gvfsmonitor.h"
42 #include "gvfsjobopenforread.h"
43 #include "gvfsjobread.h"
44 #include "gvfsjobseekread.h"
45 #include "gvfsjobopenforwrite.h"
46 #include "gvfsjobwrite.h"
47 #include "gvfsjobclosewrite.h"
48 #include "gvfsjobseekwrite.h"
49 #include "gvfsjobsetdisplayname.h"
50 #include "gvfsjobmountmountable.h"
51 #include "gvfsjobqueryinfo.h"
52 #include "gvfsjobdelete.h"
53 #include "gvfsjobqueryfsinfo.h"
54 #include "gvfsjobqueryattributes.h"
55 #include "gvfsjobenumerate.h"
56 #include "gvfsjobcreatemonitor.h"
57 #include "gvfsdaemonprotocol.h"
58
59 typedef struct {
60 char *filename;
61 char *display_name;
62 GIcon *icon;
63 GIcon *symbolic_icon;
64 GFile *root;
65 int prio;
66 gchar *unix_device_file;
67 gboolean can_mount;
68 gboolean can_unmount;
69 gboolean can_eject;
70 gboolean can_start;
71 gboolean can_start_degraded;
72 gboolean can_stop;
73 gboolean can_poll_for_media;
74 gboolean is_media_check_automatic;
75 GDriveStartStopType start_stop_type;
76
77 GDrive *drive;
78 GVolume *volume;
79 GMount *mount;
80 } ComputerFile;
81
82 static ComputerFile root = { "/" };
83
84 struct _GVfsBackendComputer
85 {
86 GVfsBackend parent_instance;
87
88 GVolumeMonitor *volume_monitor;
89
90 GVfsMonitor *root_monitor;
91
92 GList *files;
93
94 guint recompute_idle_tag;
95
96 GMountSpec *mount_spec;
97 };
98
G_DEFINE_TYPE(GVfsBackendComputer,g_vfs_backend_computer,G_VFS_TYPE_BACKEND)99 G_DEFINE_TYPE (GVfsBackendComputer, g_vfs_backend_computer, G_VFS_TYPE_BACKEND)
100
101 static void
102 computer_file_free (ComputerFile *file)
103 {
104 g_free (file->unix_device_file);
105 g_free (file->filename);
106 g_free (file->display_name);
107 if (file->icon)
108 g_object_unref (file->icon);
109 if (file->symbolic_icon)
110 g_object_unref (file->symbolic_icon);
111 if (file->root)
112 g_object_unref (file->root);
113
114 if (file->drive)
115 g_object_unref (file->drive);
116 if (file->volume)
117 g_object_unref (file->volume);
118 if (file->mount)
119 g_object_unref (file->mount);
120
121 g_slice_free (ComputerFile, file);
122 }
123
124 /* Assumes filename equal */
125 static gboolean
computer_file_equal(ComputerFile * a,ComputerFile * b)126 computer_file_equal (ComputerFile *a,
127 ComputerFile *b)
128 {
129 if (strcmp (a->display_name, b->display_name) != 0)
130 return FALSE;
131
132 if (!g_icon_equal (a->icon, b->icon))
133 return FALSE;
134
135 if (!g_icon_equal (a->symbolic_icon, b->symbolic_icon))
136 return FALSE;
137
138 if ((a->root != NULL && b->root != NULL &&
139 !g_file_equal (a->root, b->root)) ||
140 (a->root != NULL && b->root == NULL) ||
141 (a->root == NULL && b->root != NULL))
142 return FALSE;
143
144 if (a->prio != b->prio)
145 return FALSE;
146
147 if (a->can_mount != b->can_mount ||
148 a->can_unmount != b->can_unmount ||
149 a->can_eject != b->can_eject ||
150 a->can_start != b->can_start ||
151 a->can_start_degraded != b->can_start_degraded ||
152 a->can_stop != b->can_stop ||
153 a->can_poll_for_media != b->can_poll_for_media ||
154 a->is_media_check_automatic != b->is_media_check_automatic ||
155 a->start_stop_type != b->start_stop_type)
156 return FALSE;
157
158 return TRUE;
159 }
160
161 static void object_changed (GVolumeMonitor *monitor,
162 gpointer object,
163 GVfsBackendComputer *backend);
164
165 static void
g_vfs_backend_computer_finalize(GObject * object)166 g_vfs_backend_computer_finalize (GObject *object)
167 {
168 GVfsBackendComputer *backend;
169
170 backend = G_VFS_BACKEND_COMPUTER (object);
171
172 if (backend->volume_monitor)
173 {
174 g_signal_handlers_disconnect_by_func(backend->volume_monitor, object_changed, backend);
175 g_object_unref (backend->volume_monitor);
176 }
177
178 g_mount_spec_unref (backend->mount_spec);
179
180 if (backend->recompute_idle_tag)
181 {
182 g_source_remove (backend->recompute_idle_tag);
183 backend->recompute_idle_tag = 0;
184 }
185
186 g_object_unref (backend->root_monitor);
187
188 if (G_OBJECT_CLASS (g_vfs_backend_computer_parent_class)->finalize)
189 (*G_OBJECT_CLASS (g_vfs_backend_computer_parent_class)->finalize) (object);
190 }
191
192 static void
g_vfs_backend_computer_init(GVfsBackendComputer * computer_backend)193 g_vfs_backend_computer_init (GVfsBackendComputer *computer_backend)
194 {
195 GVfsBackend *backend = G_VFS_BACKEND (computer_backend);
196 GMountSpec *mount_spec;
197
198 g_vfs_backend_set_display_name (backend, _("Computer"));
199 g_vfs_backend_set_icon_name (backend, "computer");
200 g_vfs_backend_set_symbolic_icon_name (backend, "computer-symbolic");
201 g_vfs_backend_set_user_visible (backend, FALSE);
202
203 mount_spec = g_mount_spec_new ("computer");
204 g_vfs_backend_set_mount_spec (backend, mount_spec);
205 computer_backend->mount_spec = mount_spec;
206 }
207
208 static gboolean
filename_is_used(GList * files,const char * filename)209 filename_is_used (GList *files, const char *filename)
210 {
211 ComputerFile *file;
212
213 while (files != NULL)
214 {
215 file = files->data;
216
217 if (file->filename == NULL)
218 return FALSE;
219
220 if (strcmp (file->filename, filename) == 0)
221 return TRUE;
222
223 files = files->next;
224 }
225 return FALSE;
226 }
227
228 static int
sort_file_by_filename(ComputerFile * a,ComputerFile * b)229 sort_file_by_filename (ComputerFile *a, ComputerFile *b)
230 {
231 return strcmp (a->filename, b->filename);
232 }
233
234 static void
convert_slashes(char * str)235 convert_slashes (char *str)
236 {
237 char *s;
238
239 while ((s = strchr (str, '/')) != NULL)
240 *s = '\\';
241 }
242
243 static void
update_from_files(GVfsBackendComputer * backend,GList * files)244 update_from_files (GVfsBackendComputer *backend,
245 GList *files)
246 {
247 GList *old_files;
248 GList *oldl, *newl;
249 char *filename;
250 ComputerFile *old, *new;
251 int cmp;
252
253 old_files = backend->files;
254 backend->files = files;
255
256 /* Generate change events */
257 oldl = old_files;
258 newl = files;
259 while (oldl != NULL || newl != NULL)
260 {
261 if (oldl == NULL)
262 {
263 cmp = 1;
264 new = newl->data;
265 old = NULL;
266 }
267 else if (newl == NULL)
268 {
269 cmp = -1;
270 new = NULL;
271 old = oldl->data;
272 }
273 else
274 {
275 new = newl->data;
276 old = oldl->data;
277 cmp = strcmp (old->filename, new->filename);
278 }
279
280 if (cmp == 0)
281 {
282 if (!computer_file_equal (old, new))
283 {
284 filename = g_strconcat ("/", new->filename, NULL);
285 g_vfs_monitor_emit_event (backend->root_monitor,
286 G_FILE_MONITOR_EVENT_CHANGED,
287 filename,
288 NULL);
289 g_free (filename);
290 }
291
292 oldl = oldl->next;
293 newl = newl->next;
294 }
295 else if (cmp < 0)
296 {
297 filename = g_strconcat ("/", old->filename, NULL);
298 g_vfs_monitor_emit_event (backend->root_monitor,
299 G_FILE_MONITOR_EVENT_DELETED,
300 filename,
301 NULL);
302 g_free (filename);
303 oldl = oldl->next;
304 }
305 else
306 {
307 filename = g_strconcat ("/", new->filename, NULL);
308 g_vfs_monitor_emit_event (backend->root_monitor,
309 G_FILE_MONITOR_EVENT_CREATED,
310 filename,
311 NULL);
312 g_free (filename);
313 newl = newl->next;
314 }
315 }
316
317 g_list_foreach (old_files, (GFunc)computer_file_free, NULL);
318 }
319
320 static void
recompute_files(GVfsBackendComputer * backend)321 recompute_files (GVfsBackendComputer *backend)
322 {
323 GVolumeMonitor *volume_monitor;
324 GList *drives, *volumes, *mounts, *l, *ll;
325 GDrive *drive;
326 GVolume *volume;
327 GMount *mount;
328 ComputerFile *file;
329 GList *files;
330 char *basename, *filename;
331 const char *extension;
332 int uniq;
333 gchar *s;
334 gchar *display_name;
335 gchar *drive_name;
336
337 volume_monitor = backend->volume_monitor;
338
339 files = NULL;
340
341 /* first go through all connected drives */
342 drives = g_volume_monitor_get_connected_drives (volume_monitor);
343 for (l = drives; l != NULL; l = l->next)
344 {
345 drive = l->data;
346
347 volumes = g_drive_get_volumes (drive);
348 if (volumes != NULL)
349 {
350 for (ll = volumes; ll != NULL; ll = ll->next)
351 {
352 volume = ll->data;
353
354 file = g_slice_new0 (ComputerFile);
355 file->drive = g_object_ref (drive);
356 file->volume = volume; /* Takes ref */
357 file->mount = g_volume_get_mount (volume);
358 file->prio = -3;
359 files = g_list_prepend (files, file);
360 }
361 g_list_free (volumes);
362 }
363 else
364 {
365 /* No volume, single drive */
366
367 file = g_slice_new0 (ComputerFile);
368 file->drive = g_object_ref (drive);
369 file->volume = NULL;
370 file->mount = NULL;
371 file->prio = -3;
372
373 files = g_list_prepend (files, file);
374 }
375
376 g_object_unref (drive);
377 }
378 g_list_free (drives);
379
380 /* add all volumes that is not associated with a drive */
381 volumes = g_volume_monitor_get_volumes (volume_monitor);
382 for (l = volumes; l != NULL; l = l->next)
383 {
384 volume = l->data;
385 drive = g_volume_get_drive (volume);
386 if (drive == NULL)
387 {
388 file = g_slice_new0 (ComputerFile);
389 file->drive = NULL;
390 file->volume = g_object_ref (volume);
391 file->mount = g_volume_get_mount (volume);
392 file->prio = -2;
393
394 files = g_list_prepend (files, file);
395 }
396 else
397 g_object_unref (drive);
398
399 g_object_unref (volume);
400 }
401 g_list_free (volumes);
402
403 /* add mounts that has no volume (/etc/mtab mounts, ftp, sftp,...) */
404 mounts = g_volume_monitor_get_mounts (volume_monitor);
405 for (l = mounts; l != NULL; l = l->next)
406 {
407 mount = l->data;
408 volume = g_mount_get_volume (mount);
409 if (volume == NULL && !g_mount_is_shadowed (mount))
410 {
411 file = g_slice_new0 (ComputerFile);
412 file->drive = NULL;
413 file->volume = NULL;
414 file->mount = g_object_ref (mount);
415 file->prio = -1;
416
417 files = g_list_prepend (files, file);
418 }
419 else
420 g_object_unref (volume);
421
422 g_object_unref (mount);
423 }
424 g_list_free (mounts);
425
426 files = g_list_reverse (files);
427
428 for (l = files; l != NULL; l = l->next)
429 {
430 file = l->data;
431
432 if (file->mount)
433 {
434 if (file->drive != NULL)
435 {
436 drive_name = g_drive_get_name (file->drive);
437 s = g_mount_get_name (file->mount);
438 display_name = g_strdup_printf ("%s: %s", drive_name, s);
439 g_free (s);
440 g_free (drive_name);
441 }
442 else
443 {
444 display_name = g_mount_get_name (file->mount);
445 }
446 if (file->volume != NULL)
447 file->unix_device_file = g_volume_get_identifier (file->volume,
448 G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
449 file->icon = g_mount_get_icon (file->mount);
450 file->symbolic_icon = g_mount_get_symbolic_icon (file->mount);
451 file->display_name = display_name;
452 file->root = g_mount_get_default_location (file->mount);
453 file->can_unmount = g_mount_can_unmount (file->mount);
454 file->can_eject = g_mount_can_eject (file->mount);
455 }
456 else if (file->volume)
457 {
458 if (file->drive != NULL)
459 {
460 drive_name = g_drive_get_name (file->drive);
461 s = g_volume_get_name (file->volume);
462 display_name = g_strdup_printf ("%s: %s", drive_name, s);
463 g_free (s);
464 g_free (drive_name);
465 }
466 else
467 {
468 display_name = g_volume_get_name (file->volume);
469 }
470 file->unix_device_file = g_volume_get_identifier (file->volume,
471 G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
472 file->icon = g_volume_get_icon (file->volume);
473 file->symbolic_icon = g_volume_get_symbolic_icon (file->volume);
474 file->display_name = display_name;
475 file->can_mount = g_volume_can_mount (file->volume);
476 file->root = NULL;
477 file->can_eject = g_volume_can_eject (file->volume);
478 }
479 else /* drive */
480 {
481 file->unix_device_file = g_drive_get_identifier (file->drive,
482 G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
483 file->icon = g_drive_get_icon (file->drive);
484 file->symbolic_icon = g_drive_get_symbolic_icon (file->drive);
485 file->display_name = g_drive_get_name (file->drive);
486 file->can_eject = g_drive_can_eject (file->drive);
487 file->can_mount = ! g_drive_is_media_removable (file->drive) || ! g_drive_is_media_check_automatic (file->drive) || g_drive_has_media (file->drive);
488 }
489
490 if (file->drive)
491 {
492 file->can_start = g_drive_can_start (file->drive);
493 file->can_start_degraded = g_drive_can_start_degraded (file->drive);
494 file->can_stop = g_drive_can_stop (file->drive);
495 file->can_poll_for_media = g_drive_can_poll_for_media (file->drive);
496 file->is_media_check_automatic = g_drive_is_media_check_automatic (file->drive);
497 file->start_stop_type = g_drive_get_start_stop_type (file->drive);
498 if (file->can_start)
499 file->can_mount = FALSE;
500 basename = g_drive_get_name (file->drive);
501 extension = ".drive";
502 }
503 else if (file->volume)
504 {
505 basename = g_volume_get_name (file->volume);
506 extension = ".volume";
507 }
508 else /* mount */
509 {
510 basename = g_mount_get_name (file->mount);
511 extension = ".mount";
512 }
513
514 convert_slashes (basename); /* No slashes in filenames */
515 uniq = 1;
516 filename = g_strconcat (basename, extension, NULL);
517 while (filename_is_used (files, filename))
518 {
519 g_free (filename);
520 filename = g_strdup_printf ("%s-%d%s",
521 basename,
522 uniq++,
523 extension);
524 }
525
526 g_free (basename);
527 file->filename = filename;
528 }
529
530 file = g_slice_new0 (ComputerFile);
531 file->filename = g_strdup ("root.link");
532 file->display_name = g_strdup (_("File System"));
533 file->icon = g_themed_icon_new_with_default_fallbacks ("drive-harddisk-system");
534 file->symbolic_icon = g_themed_icon_new_with_default_fallbacks ("drive-harddisk-system-symbolic");
535 file->root = g_file_new_for_path ("/");
536 file->prio = 0;
537
538 files = g_list_prepend (files, file);
539
540 files = g_list_sort (files, (GCompareFunc)sort_file_by_filename);
541
542 update_from_files (backend, files);
543 }
544
545 static gboolean
recompute_files_in_idle(GVfsBackendComputer * backend)546 recompute_files_in_idle (GVfsBackendComputer *backend)
547 {
548 backend->recompute_idle_tag = 0;
549
550 recompute_files (backend);
551
552 return FALSE;
553 }
554
555 static void
object_changed(GVolumeMonitor * monitor,gpointer object,GVfsBackendComputer * backend)556 object_changed (GVolumeMonitor *monitor,
557 gpointer object,
558 GVfsBackendComputer *backend)
559 {
560 if (backend->recompute_idle_tag == 0)
561 backend->recompute_idle_tag =
562 g_idle_add ((GSourceFunc)recompute_files_in_idle,
563 backend);
564 }
565
566 static gboolean
try_mount(GVfsBackend * backend,GVfsJobMount * job,GMountSpec * mount_spec,GMountSource * mount_source,gboolean is_automount)567 try_mount (GVfsBackend *backend,
568 GVfsJobMount *job,
569 GMountSpec *mount_spec,
570 GMountSource *mount_source,
571 gboolean is_automount)
572 {
573 GVfsBackendComputer *computer_backend = G_VFS_BACKEND_COMPUTER (backend);
574 int i;
575 char *signals[] = {
576 "volume-added",
577 "volume-removed",
578 "volume-changed",
579 "mount-added",
580 "mount-removed",
581 "mount-changed",
582 "drive-connected",
583 "drive-disconnected",
584 "drive-changed",
585 NULL
586 };
587
588 computer_backend->volume_monitor = g_volume_monitor_get ();
589
590 /* TODO: connect all signals to object_changed */
591
592 for (i = 0; signals[i] != NULL; i++)
593 g_signal_connect_data (computer_backend->volume_monitor,
594 signals[i],
595 (GCallback)object_changed,
596 backend,
597 NULL, 0);
598
599 computer_backend->root_monitor = g_vfs_monitor_new (backend);
600
601 recompute_files (computer_backend);
602
603 g_vfs_job_succeeded (G_VFS_JOB (job));
604
605 return TRUE;
606 }
607
608 static ComputerFile *
lookup(GVfsBackendComputer * backend,GVfsJob * job,const char * filename)609 lookup (GVfsBackendComputer *backend,
610 GVfsJob *job,
611 const char *filename)
612 {
613 GList *l;
614 ComputerFile *file;
615
616 if (*filename != '/')
617 goto out;
618
619 while (*filename == '/')
620 filename++;
621
622 if (*filename == 0)
623 return &root;
624
625 if (strchr (filename, '/') != NULL)
626 goto out;
627
628 for (l = backend->files; l != NULL; l = l->next)
629 {
630 file = l->data;
631
632 if (strcmp (file->filename, filename) == 0)
633 return file;
634 }
635
636 out:
637 g_vfs_job_failed (job, G_IO_ERROR,
638 G_IO_ERROR_NOT_FOUND,
639 _("File doesn’t exist"));
640 return NULL;
641 }
642
643
644 static gboolean
try_open_for_read(GVfsBackend * backend,GVfsJobOpenForRead * job,const char * filename)645 try_open_for_read (GVfsBackend *backend,
646 GVfsJobOpenForRead *job,
647 const char *filename)
648 {
649 ComputerFile *file;
650
651 file = lookup (G_VFS_BACKEND_COMPUTER (backend),
652 G_VFS_JOB (job), filename);
653
654 if (file == &root)
655 g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
656 G_IO_ERROR_IS_DIRECTORY,
657 _("Can’t open directory"));
658 else if (file != NULL)
659 g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
660 G_IO_ERROR_NOT_SUPPORTED,
661 _("Can’t open mountable file"));
662 return TRUE;
663 }
664
665 static void
file_info_from_file(ComputerFile * file,GFileInfo * info)666 file_info_from_file (ComputerFile *file,
667 GFileInfo *info)
668 {
669 char *uri;
670
671 g_file_info_set_name (info, file->filename);
672 g_file_info_set_display_name (info, file->display_name);
673
674 if (file->icon)
675 g_file_info_set_icon (info, file->icon);
676 if (file->symbolic_icon)
677 g_file_info_set_symbolic_icon (info, file->symbolic_icon);
678
679 if (file->root)
680 {
681 uri = g_file_get_uri (file->root);
682
683 g_file_info_set_attribute_string (info,
684 G_FILE_ATTRIBUTE_STANDARD_TARGET_URI,
685 uri);
686 g_free (uri);
687 }
688
689 g_file_info_set_sort_order (info, file->prio);
690
691 g_file_info_set_file_type (info, G_FILE_TYPE_MOUNTABLE);
692 if (file->unix_device_file != NULL)
693 g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_MOUNTABLE_UNIX_DEVICE_FILE, file->unix_device_file);
694 g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_MOUNT, file->can_mount);
695 g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_UNMOUNT, file->can_unmount);
696 g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_EJECT, file->can_eject);
697 g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_START, file->can_start);
698 g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_START_DEGRADED, file->can_start_degraded);
699 g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_STOP, file->can_stop);
700 g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_POLL, file->can_poll_for_media);
701 g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_MOUNTABLE_IS_MEDIA_CHECK_AUTOMATIC, file->is_media_check_automatic);
702 g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_MOUNTABLE_START_STOP_TYPE, file->start_stop_type);
703
704 g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE, FALSE);
705 g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME, FALSE);
706 g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE, FALSE);
707 g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH, FALSE);
708 }
709
710 static gboolean
try_enumerate(GVfsBackend * backend,GVfsJobEnumerate * job,const char * filename,GFileAttributeMatcher * attribute_matcher,GFileQueryInfoFlags flags)711 try_enumerate (GVfsBackend *backend,
712 GVfsJobEnumerate *job,
713 const char *filename,
714 GFileAttributeMatcher *attribute_matcher,
715 GFileQueryInfoFlags flags)
716 {
717 ComputerFile *file;
718 GList *l;
719 GFileInfo *info;
720
721 file = lookup (G_VFS_BACKEND_COMPUTER (backend),
722 G_VFS_JOB (job), filename);
723
724 if (file != &root)
725 {
726 if (file != NULL)
727 g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
728 G_IO_ERROR_NOT_DIRECTORY,
729 _("The file is not a directory"));
730 return TRUE;
731 }
732
733 g_vfs_job_succeeded (G_VFS_JOB (job));
734
735 /* Enumerate root */
736 for (l = G_VFS_BACKEND_COMPUTER (backend)->files; l != NULL; l = l->next)
737 {
738 file = l->data;
739
740 info = g_file_info_new ();
741
742 file_info_from_file (file, info);
743 g_vfs_job_enumerate_add_info (job, info);
744 g_object_unref (info);
745 }
746
747 g_vfs_job_enumerate_done (job);
748
749 return TRUE;
750 }
751
752 static gboolean
try_query_info(GVfsBackend * backend,GVfsJobQueryInfo * job,const char * filename,GFileQueryInfoFlags flags,GFileInfo * info,GFileAttributeMatcher * matcher)753 try_query_info (GVfsBackend *backend,
754 GVfsJobQueryInfo *job,
755 const char *filename,
756 GFileQueryInfoFlags flags,
757 GFileInfo *info,
758 GFileAttributeMatcher *matcher)
759 {
760 ComputerFile *file;
761
762 file = lookup (G_VFS_BACKEND_COMPUTER (backend),
763 G_VFS_JOB (job), filename);
764
765 if (file == &root)
766 {
767 GIcon *icon;
768
769 g_file_info_set_name (info, "/");
770 g_file_info_set_file_type (info, G_FILE_TYPE_DIRECTORY);
771 g_file_info_set_display_name (info, _("Computer"));
772 icon = g_themed_icon_new ("computer");
773 g_file_info_set_icon (info, icon);
774 g_object_unref (icon);
775 icon = g_themed_icon_new ("computer-symbolic");
776 g_file_info_set_symbolic_icon (info, icon);
777 g_object_unref (icon);
778 g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE, FALSE);
779 g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE, FALSE);
780 g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH, FALSE);
781 g_file_info_set_content_type (info, "inode/directory");
782
783 g_vfs_job_succeeded (G_VFS_JOB (job));
784 }
785 else if (file != NULL)
786 {
787 file_info_from_file (file, info);
788 g_vfs_job_succeeded (G_VFS_JOB (job));
789 }
790
791 return TRUE;
792 }
793
794 static gboolean
try_create_dir_monitor(GVfsBackend * backend,GVfsJobCreateMonitor * job,const char * filename,GFileMonitorFlags flags)795 try_create_dir_monitor (GVfsBackend *backend,
796 GVfsJobCreateMonitor *job,
797 const char *filename,
798 GFileMonitorFlags flags)
799 {
800 ComputerFile *file;
801 GVfsBackendComputer *computer_backend;
802
803 computer_backend = G_VFS_BACKEND_COMPUTER (backend);
804
805 file = lookup (computer_backend,
806 G_VFS_JOB (job), filename);
807
808 if (file != &root)
809 {
810 g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
811 G_IO_ERROR_NOT_SUPPORTED,
812 _("Operation not supported"));
813
814 return TRUE;
815 }
816
817 g_vfs_job_create_monitor_set_monitor (job,
818 computer_backend->root_monitor);
819 g_vfs_job_succeeded (G_VFS_JOB (job));
820
821 return TRUE;
822 }
823
824 static void
mount_volume_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)825 mount_volume_cb (GObject *source_object,
826 GAsyncResult *res,
827 gpointer user_data)
828 {
829 GVfsJobMountMountable *job = user_data;
830 GError *error;
831 GMount *mount;
832 GVolume *volume;
833 GFile *root;
834 char *uri;
835
836 volume = G_VOLUME (source_object);
837
838 error = NULL;
839 if (g_volume_mount_finish (volume, res, &error))
840 {
841 mount = g_volume_get_mount (volume);
842
843 if (mount)
844 {
845 root = g_mount_get_root (mount);
846 uri = g_file_get_uri (root);
847 g_vfs_job_mount_mountable_set_target_uri (job,
848 uri,
849 FALSE);
850 g_free (uri);
851 g_object_unref (root);
852 g_object_unref (mount);
853 g_vfs_job_succeeded (G_VFS_JOB (job));
854 }
855 else
856 g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
857 G_IO_ERROR_FAILED,
858 _("Internal error: %s"), "No mount object for mounted volume");
859 }
860 else
861 {
862 g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
863 g_error_free (error);
864 }
865 }
866
867 static void
mount_volume_from_drive(GDrive * drive,GVfsJob * job,GMountOperation * mount_op)868 mount_volume_from_drive (GDrive *drive,
869 GVfsJob *job,
870 GMountOperation *mount_op)
871 {
872 GList *volumes;
873 GVolume *volume;
874
875 volumes = g_drive_get_volumes (drive);
876 if (volumes)
877 {
878 volume = G_VOLUME (volumes->data);
879 g_volume_mount (volume,
880 0,
881 mount_op,
882 G_VFS_JOB (job)->cancellable,
883 mount_volume_cb,
884 job);
885 }
886 else
887 {
888 g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
889 G_IO_ERROR_NOT_SUPPORTED,
890 _("Can’t mount file"));
891 }
892
893 g_list_free_full (volumes, g_object_unref);
894 }
895
896 static void
report_no_media_error(GVfsJob * job)897 report_no_media_error (GVfsJob *job)
898 {
899 g_vfs_job_failed (job, G_IO_ERROR,
900 G_IO_ERROR_NOT_SUPPORTED,
901 _("No medium in the drive"));
902 }
903
904 typedef struct {
905 GVfsJobMountMountable *job;
906 GMountOperation *mount_op;
907 } PollForMediaData;
908
909 static void
poll_for_media_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)910 poll_for_media_cb (GObject *source_object,
911 GAsyncResult *res,
912 gpointer user_data)
913 {
914 PollForMediaData *data = user_data;
915 GDrive *drive;
916 GError *error;
917
918 drive = G_DRIVE (source_object);
919 error = NULL;
920
921 if (g_drive_poll_for_media_finish (drive, res, &error))
922 {
923 gboolean has_media;
924 has_media = g_drive_has_media (drive);
925
926 if (!has_media)
927 {
928 report_no_media_error (G_VFS_JOB (data->job));
929 }
930 else
931 {
932 mount_volume_from_drive (drive, G_VFS_JOB (data->job), data->mount_op);
933 g_slice_free (PollForMediaData, data);
934 }
935 }
936 else
937 {
938 g_vfs_job_failed_from_error (G_VFS_JOB (data->job), error);
939 g_error_free (error);
940 }
941 }
942
943 static gboolean
try_mount_mountable(GVfsBackend * backend,GVfsJobMountMountable * job,const char * filename,GMountSource * mount_source)944 try_mount_mountable (GVfsBackend *backend,
945 GVfsJobMountMountable *job,
946 const char *filename,
947 GMountSource *mount_source)
948 {
949 ComputerFile *file;
950 GMountOperation *mount_op;
951
952 file = lookup (G_VFS_BACKEND_COMPUTER (backend),
953 G_VFS_JOB (job), filename);
954
955 if (file == &root)
956 g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
957 G_IO_ERROR_NOT_MOUNTABLE_FILE,
958 _("Not a mountable file"));
959 else if (file != NULL)
960 {
961 if (file->volume)
962 {
963 mount_op = g_mount_source_get_operation (mount_source);
964 /* free mount_op when job is completed */
965 g_object_set_data_full (G_OBJECT (job), "gvfs-backend-computer-mount-op", mount_op, g_object_unref);
966 g_volume_mount (file->volume,
967 0,
968 mount_op,
969 G_VFS_JOB (job)->cancellable,
970 mount_volume_cb,
971 job);
972 }
973
974 else if (file->drive)
975 {
976 if (!g_drive_has_media (file->drive))
977 {
978 if (!g_drive_can_poll_for_media (file->drive))
979 report_no_media_error (G_VFS_JOB (job));
980 else
981 {
982 PollForMediaData *data;
983
984 data = g_slice_new0 (PollForMediaData);
985 mount_op = g_mount_source_get_operation (mount_source);
986 data->job = job;
987 data->mount_op = mount_op;
988 if (!g_drive_is_media_check_automatic (file->drive))
989 g_drive_poll_for_media (file->drive,
990 G_VFS_JOB (job)->cancellable,
991 poll_for_media_cb,
992 data);
993 else
994 report_no_media_error (G_VFS_JOB (job));
995 }
996 }
997 else
998 {
999 mount_op = g_mount_source_get_operation (mount_source);
1000 mount_volume_from_drive (file->drive, G_VFS_JOB (job), mount_op);
1001 }
1002 }
1003
1004 else
1005 {
1006 g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
1007 G_IO_ERROR_NOT_SUPPORTED,
1008 _("Can’t mount file"));
1009 }
1010 }
1011
1012 return TRUE;
1013 }
1014
1015 static void
unmount_mount_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)1016 unmount_mount_cb (GObject *source_object,
1017 GAsyncResult *res,
1018 gpointer user_data)
1019 {
1020 GVfsJobMountMountable *job = user_data;
1021 GError *error;
1022 GMount *mount;
1023
1024 mount = G_MOUNT (source_object);
1025
1026 error = NULL;
1027 if (g_mount_unmount_with_operation_finish (mount, res, &error))
1028 g_vfs_job_succeeded (G_VFS_JOB (job));
1029 else
1030 {
1031 g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
1032 g_error_free (error);
1033 }
1034 }
1035
1036
1037 static gboolean
try_unmount_mountable(GVfsBackend * backend,GVfsJobUnmountMountable * job,const char * filename,GMountUnmountFlags flags,GMountSource * mount_source)1038 try_unmount_mountable (GVfsBackend *backend,
1039 GVfsJobUnmountMountable *job,
1040 const char *filename,
1041 GMountUnmountFlags flags,
1042 GMountSource *mount_source)
1043 {
1044 ComputerFile *file;
1045 GMountOperation *mount_op;
1046
1047 file = lookup (G_VFS_BACKEND_COMPUTER (backend),
1048 G_VFS_JOB (job), filename);
1049
1050 if (file == &root)
1051 g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
1052 G_IO_ERROR_NOT_MOUNTABLE_FILE,
1053 _("Not a mountable file"));
1054 else if (file != NULL)
1055 {
1056 if (file->mount)
1057 {
1058 mount_op = g_mount_source_get_operation (mount_source);
1059 /* free mount_op when job is completed */
1060 g_object_set_data_full (G_OBJECT (job), "gvfs-backend-computer-mount-op", mount_op, g_object_unref);
1061 g_mount_unmount_with_operation (file->mount,
1062 flags,
1063 mount_op,
1064 G_VFS_JOB (job)->cancellable,
1065 unmount_mount_cb,
1066 job);
1067 }
1068 else
1069 {
1070 g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
1071 G_IO_ERROR_NOT_SUPPORTED,
1072 _("Can’t unmount file"));
1073 }
1074 }
1075
1076 return TRUE;
1077 }
1078
1079 static void
eject_mount_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)1080 eject_mount_cb (GObject *source_object,
1081 GAsyncResult *res,
1082 gpointer user_data)
1083 {
1084 GVfsJobMountMountable *job = user_data;
1085 GError *error;
1086 GMount *mount;
1087
1088 mount = G_MOUNT (source_object);
1089
1090 error = NULL;
1091 if (g_mount_eject_with_operation_finish (mount, res, &error))
1092 g_vfs_job_succeeded (G_VFS_JOB (job));
1093 else
1094 {
1095 g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
1096 g_error_free (error);
1097 }
1098 }
1099
1100 static void
eject_volume_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)1101 eject_volume_cb (GObject *source_object,
1102 GAsyncResult *res,
1103 gpointer user_data)
1104 {
1105 GVfsJobMountMountable *job = user_data;
1106 GError *error;
1107 GVolume *volume;
1108
1109 volume = G_VOLUME (source_object);
1110
1111 error = NULL;
1112 if (g_volume_eject_with_operation_finish (volume, res, &error))
1113 g_vfs_job_succeeded (G_VFS_JOB (job));
1114 else
1115 {
1116 g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
1117 g_error_free (error);
1118 }
1119 }
1120
1121
1122 static void
eject_drive_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)1123 eject_drive_cb (GObject *source_object,
1124 GAsyncResult *res,
1125 gpointer user_data)
1126 {
1127 GVfsJobMountMountable *job = user_data;
1128 GError *error;
1129 GDrive *drive;
1130
1131 drive = G_DRIVE (source_object);
1132
1133 error = NULL;
1134 if (g_drive_eject_with_operation_finish (drive, res, &error))
1135 g_vfs_job_succeeded (G_VFS_JOB (job));
1136 else
1137 {
1138 g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
1139 g_error_free (error);
1140 }
1141 }
1142
1143 static gboolean
try_eject_mountable(GVfsBackend * backend,GVfsJobUnmountMountable * job,const char * filename,GMountUnmountFlags flags,GMountSource * mount_source)1144 try_eject_mountable (GVfsBackend *backend,
1145 GVfsJobUnmountMountable *job,
1146 const char *filename,
1147 GMountUnmountFlags flags,
1148 GMountSource *mount_source)
1149 {
1150 ComputerFile *file;
1151 GMountOperation *mount_op;
1152
1153 file = lookup (G_VFS_BACKEND_COMPUTER (backend),
1154 G_VFS_JOB (job), filename);
1155
1156 if (file == &root)
1157 g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
1158 G_IO_ERROR_NOT_MOUNTABLE_FILE,
1159 _("Not a mountable file"));
1160 else if (file != NULL)
1161 {
1162 if (file->mount)
1163 {
1164 mount_op = g_mount_source_get_operation (mount_source);
1165 /* free mount_op when job is completed */
1166 g_object_set_data_full (G_OBJECT (job), "gvfs-backend-computer-mount-op", mount_op, g_object_unref);
1167 g_mount_eject_with_operation (file->mount,
1168 flags,
1169 mount_op,
1170 G_VFS_JOB (job)->cancellable,
1171 eject_mount_cb,
1172 job);
1173 }
1174 else if (file->volume)
1175 {
1176 mount_op = g_mount_source_get_operation (mount_source);
1177 /* free mount_op when job is completed */
1178 g_object_set_data_full (G_OBJECT (job), "gvfs-backend-computer-mount-op", mount_op, g_object_unref);
1179 g_volume_eject_with_operation (file->volume,
1180 flags,
1181 mount_op,
1182 G_VFS_JOB (job)->cancellable,
1183 eject_volume_cb,
1184 job);
1185 }
1186 else if (file->drive)
1187 {
1188 mount_op = g_mount_source_get_operation (mount_source);
1189 /* free mount_op when job is completed */
1190 g_object_set_data_full (G_OBJECT (job), "gvfs-backend-computer-mount-op", mount_op, g_object_unref);
1191 g_drive_eject_with_operation (file->drive,
1192 flags,
1193 mount_op,
1194 G_VFS_JOB (job)->cancellable,
1195 eject_drive_cb,
1196 job);
1197 }
1198 else
1199 {
1200 g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
1201 G_IO_ERROR_NOT_SUPPORTED,
1202 _("Can’t eject file"));
1203 }
1204 }
1205
1206 return TRUE;
1207 }
1208
1209
1210 static void
drive_start_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)1211 drive_start_cb (GObject *source_object,
1212 GAsyncResult *res,
1213 gpointer user_data)
1214 {
1215 GVfsJobStartMountable *job = user_data;
1216 GError *error;
1217 GDrive *drive;
1218
1219 drive = G_DRIVE (source_object);
1220
1221 error = NULL;
1222 if (g_drive_start_finish (drive, res, &error))
1223 {
1224 g_vfs_job_succeeded (G_VFS_JOB (job));
1225 }
1226 else
1227 {
1228 g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
1229 g_error_free (error);
1230 }
1231 }
1232
1233 static gboolean
try_start_mountable(GVfsBackend * backend,GVfsJobStartMountable * job,const char * filename,GMountSource * mount_source)1234 try_start_mountable (GVfsBackend *backend,
1235 GVfsJobStartMountable *job,
1236 const char *filename,
1237 GMountSource *mount_source)
1238 {
1239 ComputerFile *file;
1240 GMountOperation *mount_op;
1241
1242 file = lookup (G_VFS_BACKEND_COMPUTER (backend),
1243 G_VFS_JOB (job), filename);
1244
1245 if (file == &root)
1246 {
1247 g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
1248 G_IO_ERROR_NOT_MOUNTABLE_FILE,
1249 _("Not a mountable file"));
1250 }
1251 else if (file != NULL)
1252 {
1253 if (file->drive != NULL)
1254 {
1255 mount_op = g_mount_source_get_operation (mount_source);
1256 /* free mount_op when job is completed */
1257 g_object_set_data_full (G_OBJECT (job), "gvfs-backend-computer-start-op", mount_op, g_object_unref);
1258 g_drive_start (file->drive,
1259 0,
1260 mount_op,
1261 G_VFS_JOB (job)->cancellable,
1262 drive_start_cb,
1263 job);
1264 }
1265 else
1266 {
1267 g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
1268 G_IO_ERROR_NOT_SUPPORTED,
1269 _("Can’t start drive"));
1270 }
1271 }
1272 else
1273 {
1274 g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
1275 G_IO_ERROR_NOT_SUPPORTED,
1276 _("Can’t start drive"));
1277 }
1278 return TRUE;
1279 }
1280
1281
1282 static void
drive_stop_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)1283 drive_stop_cb (GObject *source_object,
1284 GAsyncResult *res,
1285 gpointer user_data)
1286 {
1287 GVfsJobStopMountable *job = user_data;
1288 GError *error;
1289 GDrive *drive;
1290
1291 drive = G_DRIVE (source_object);
1292
1293 error = NULL;
1294 if (g_drive_stop_finish (drive, res, &error))
1295 {
1296 g_vfs_job_succeeded (G_VFS_JOB (job));
1297 }
1298 else
1299 {
1300 g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
1301 g_error_free (error);
1302 }
1303 }
1304
1305 static gboolean
try_stop_mountable(GVfsBackend * backend,GVfsJobStopMountable * job,const char * filename,GMountUnmountFlags flags,GMountSource * mount_source)1306 try_stop_mountable (GVfsBackend *backend,
1307 GVfsJobStopMountable *job,
1308 const char *filename,
1309 GMountUnmountFlags flags,
1310 GMountSource *mount_source)
1311 {
1312 ComputerFile *file;
1313 GMountOperation *mount_op;
1314
1315 file = lookup (G_VFS_BACKEND_COMPUTER (backend),
1316 G_VFS_JOB (job), filename);
1317
1318 if (file == &root)
1319 {
1320 g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
1321 G_IO_ERROR_NOT_MOUNTABLE_FILE,
1322 _("Not a mountable file"));
1323 }
1324 else if (file != NULL)
1325 {
1326 if (file->drive != NULL)
1327 {
1328 mount_op = g_mount_source_get_operation (mount_source);
1329 /* free mount_op when job is completed */
1330 g_object_set_data_full (G_OBJECT (job), "gvfs-backend-computer-start-op", mount_op, g_object_unref);
1331 g_drive_stop (file->drive,
1332 flags,
1333 mount_op,
1334 G_VFS_JOB (job)->cancellable,
1335 drive_stop_cb,
1336 job);
1337 }
1338 else
1339 {
1340 g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
1341 G_IO_ERROR_NOT_SUPPORTED,
1342 _("Can’t stop drive"));
1343 }
1344 }
1345 else
1346 {
1347 g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
1348 G_IO_ERROR_NOT_SUPPORTED,
1349 _("Can’t stop drive"));
1350 }
1351 return TRUE;
1352 }
1353
1354 static void
drive_poll_for_media_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)1355 drive_poll_for_media_cb (GObject *source_object,
1356 GAsyncResult *res,
1357 gpointer user_data)
1358 {
1359 GVfsJobPollMountable *job = user_data;
1360 GError *error;
1361 GDrive *drive;
1362
1363 drive = G_DRIVE (source_object);
1364
1365 error = NULL;
1366 if (g_drive_poll_for_media_finish (drive, res, &error))
1367 {
1368 g_vfs_job_succeeded (G_VFS_JOB (job));
1369 }
1370 else
1371 {
1372 g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
1373 g_error_free (error);
1374 }
1375 }
1376
1377 static gboolean
try_poll_mountable(GVfsBackend * backend,GVfsJobPollMountable * job,const char * filename)1378 try_poll_mountable (GVfsBackend *backend,
1379 GVfsJobPollMountable *job,
1380 const char *filename)
1381 {
1382 ComputerFile *file;
1383
1384 file = lookup (G_VFS_BACKEND_COMPUTER (backend),
1385 G_VFS_JOB (job), filename);
1386
1387 if (file == &root)
1388 {
1389 g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
1390 G_IO_ERROR_NOT_MOUNTABLE_FILE,
1391 _("Not a mountable file"));
1392 }
1393 else if (file != NULL)
1394 {
1395 if (file->drive != NULL)
1396 {
1397 g_drive_poll_for_media (file->drive,
1398 G_VFS_JOB (job)->cancellable,
1399 drive_poll_for_media_cb,
1400 job);
1401 }
1402 else
1403 {
1404 g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
1405 G_IO_ERROR_NOT_SUPPORTED,
1406 _("Can’t poll file"));
1407 }
1408 }
1409 else
1410 {
1411 g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
1412 G_IO_ERROR_NOT_SUPPORTED,
1413 _("Can’t poll file"));
1414 }
1415 return TRUE;
1416 }
1417
1418 static gboolean
try_query_fs_info(GVfsBackend * backend,GVfsJobQueryFsInfo * job,const char * filename,GFileInfo * info,GFileAttributeMatcher * matcher)1419 try_query_fs_info (GVfsBackend *backend,
1420 GVfsJobQueryFsInfo *job,
1421 const char *filename,
1422 GFileInfo *info,
1423 GFileAttributeMatcher *matcher)
1424 {
1425 g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "computer");
1426 g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, FALSE);
1427 g_vfs_job_succeeded (G_VFS_JOB (job));
1428 return TRUE;
1429 }
1430
1431 static void
g_vfs_backend_computer_class_init(GVfsBackendComputerClass * klass)1432 g_vfs_backend_computer_class_init (GVfsBackendComputerClass *klass)
1433 {
1434 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1435 GVfsBackendClass *backend_class = G_VFS_BACKEND_CLASS (klass);
1436
1437 gobject_class->finalize = g_vfs_backend_computer_finalize;
1438
1439 backend_class->try_mount = try_mount;
1440 backend_class->try_open_for_read = try_open_for_read;
1441 backend_class->try_query_info = try_query_info;
1442 backend_class->try_query_fs_info = try_query_fs_info;
1443 backend_class->try_enumerate = try_enumerate;
1444 backend_class->try_create_dir_monitor = try_create_dir_monitor;
1445 backend_class->try_mount_mountable = try_mount_mountable;
1446 backend_class->try_unmount_mountable = try_unmount_mountable;
1447 backend_class->try_eject_mountable = try_eject_mountable;
1448 backend_class->try_start_mountable = try_start_mountable;
1449 backend_class->try_stop_mountable = try_stop_mountable;
1450 backend_class->try_poll_mountable = try_poll_mountable;
1451 }
1452