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