gvfs/daemon/gvfsbackendcomputer.c

1453 lines
41 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* GIO - GLib Input, Output and Streaming Library
*
* Copyright (C) 2006-2007 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
* Authors: Alexander Larsson <alexl@redhat.com>
* Cosimo Cecchi <cosimoc@gnome.org>
*/
#include <config.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <glib.h>
#include <glib/gstdio.h>
#include <glib/gi18n.h>
#include <gio/gio.h>
#include <gio/gunixmounts.h>
#include "gvfsbackendcomputer.h"
#include "gvfsmonitor.h"
#include "gvfsjobopenforread.h"
#include "gvfsjobread.h"
#include "gvfsjobseekread.h"
#include "gvfsjobopenforwrite.h"
#include "gvfsjobwrite.h"
#include "gvfsjobclosewrite.h"
#include "gvfsjobseekwrite.h"
#include "gvfsjobsetdisplayname.h"
#include "gvfsjobmountmountable.h"
#include "gvfsjobqueryinfo.h"
#include "gvfsjobdelete.h"
#include "gvfsjobqueryfsinfo.h"
#include "gvfsjobqueryattributes.h"
#include "gvfsjobenumerate.h"
#include "gvfsjobcreatemonitor.h"
#include "gvfsdaemonprotocol.h"
typedef struct {
char *filename;
char *display_name;
GIcon *icon;
GIcon *symbolic_icon;
GFile *root;
int prio;
gchar *unix_device_file;
gboolean can_mount;
gboolean can_unmount;
gboolean can_eject;
gboolean can_start;
gboolean can_start_degraded;
gboolean can_stop;
gboolean can_poll_for_media;
gboolean is_media_check_automatic;
GDriveStartStopType start_stop_type;
GDrive *drive;
GVolume *volume;
GMount *mount;
} ComputerFile;
static ComputerFile root = { "/" };
struct _GVfsBackendComputer
{
GVfsBackend parent_instance;
GVolumeMonitor *volume_monitor;
GVfsMonitor *root_monitor;
GList *files;
guint recompute_idle_tag;
GMountSpec *mount_spec;
};
G_DEFINE_TYPE (GVfsBackendComputer, g_vfs_backend_computer, G_VFS_TYPE_BACKEND)
static void
computer_file_free (ComputerFile *file)
{
g_free (file->unix_device_file);
g_free (file->filename);
g_free (file->display_name);
if (file->icon)
g_object_unref (file->icon);
if (file->symbolic_icon)
g_object_unref (file->symbolic_icon);
if (file->root)
g_object_unref (file->root);
if (file->drive)
g_object_unref (file->drive);
if (file->volume)
g_object_unref (file->volume);
if (file->mount)
g_object_unref (file->mount);
g_slice_free (ComputerFile, file);
}
/* Assumes filename equal */
static gboolean
computer_file_equal (ComputerFile *a,
ComputerFile *b)
{
if (strcmp (a->display_name, b->display_name) != 0)
return FALSE;
if (!g_icon_equal (a->icon, b->icon))
return FALSE;
if (!g_icon_equal (a->symbolic_icon, b->symbolic_icon))
return FALSE;
if ((a->root != NULL && b->root != NULL &&
!g_file_equal (a->root, b->root)) ||
(a->root != NULL && b->root == NULL) ||
(a->root == NULL && b->root != NULL))
return FALSE;
if (a->prio != b->prio)
return FALSE;
if (a->can_mount != b->can_mount ||
a->can_unmount != b->can_unmount ||
a->can_eject != b->can_eject ||
a->can_start != b->can_start ||
a->can_start_degraded != b->can_start_degraded ||
a->can_stop != b->can_stop ||
a->can_poll_for_media != b->can_poll_for_media ||
a->is_media_check_automatic != b->is_media_check_automatic ||
a->start_stop_type != b->start_stop_type)
return FALSE;
return TRUE;
}
static void object_changed (GVolumeMonitor *monitor,
gpointer object,
GVfsBackendComputer *backend);
static void
g_vfs_backend_computer_finalize (GObject *object)
{
GVfsBackendComputer *backend;
backend = G_VFS_BACKEND_COMPUTER (object);
if (backend->volume_monitor)
{
g_signal_handlers_disconnect_by_func(backend->volume_monitor, object_changed, backend);
g_object_unref (backend->volume_monitor);
}
g_mount_spec_unref (backend->mount_spec);
if (backend->recompute_idle_tag)
{
g_source_remove (backend->recompute_idle_tag);
backend->recompute_idle_tag = 0;
}
g_object_unref (backend->root_monitor);
if (G_OBJECT_CLASS (g_vfs_backend_computer_parent_class)->finalize)
(*G_OBJECT_CLASS (g_vfs_backend_computer_parent_class)->finalize) (object);
}
static void
g_vfs_backend_computer_init (GVfsBackendComputer *computer_backend)
{
GVfsBackend *backend = G_VFS_BACKEND (computer_backend);
GMountSpec *mount_spec;
g_vfs_backend_set_display_name (backend, _("Computer"));
g_vfs_backend_set_icon_name (backend, "computer");
g_vfs_backend_set_symbolic_icon_name (backend, "computer-symbolic");
g_vfs_backend_set_user_visible (backend, FALSE);
mount_spec = g_mount_spec_new ("computer");
g_vfs_backend_set_mount_spec (backend, mount_spec);
computer_backend->mount_spec = mount_spec;
}
static gboolean
filename_is_used (GList *files, const char *filename)
{
ComputerFile *file;
while (files != NULL)
{
file = files->data;
if (file->filename == NULL)
return FALSE;
if (strcmp (file->filename, filename) == 0)
return TRUE;
files = files->next;
}
return FALSE;
}
static int
sort_file_by_filename (ComputerFile *a, ComputerFile *b)
{
return strcmp (a->filename, b->filename);
}
static void
convert_slashes (char *str)
{
char *s;
while ((s = strchr (str, '/')) != NULL)
*s = '\\';
}
static void
update_from_files (GVfsBackendComputer *backend,
GList *files)
{
GList *old_files;
GList *oldl, *newl;
char *filename;
ComputerFile *old, *new;
int cmp;
old_files = backend->files;
backend->files = files;
/* Generate change events */
oldl = old_files;
newl = files;
while (oldl != NULL || newl != NULL)
{
if (oldl == NULL)
{
cmp = 1;
new = newl->data;
old = NULL;
}
else if (newl == NULL)
{
cmp = -1;
new = NULL;
old = oldl->data;
}
else
{
new = newl->data;
old = oldl->data;
cmp = strcmp (old->filename, new->filename);
}
if (cmp == 0)
{
if (!computer_file_equal (old, new))
{
filename = g_strconcat ("/", new->filename, NULL);
g_vfs_monitor_emit_event (backend->root_monitor,
G_FILE_MONITOR_EVENT_CHANGED,
filename,
NULL);
g_free (filename);
}
oldl = oldl->next;
newl = newl->next;
}
else if (cmp < 0)
{
filename = g_strconcat ("/", old->filename, NULL);
g_vfs_monitor_emit_event (backend->root_monitor,
G_FILE_MONITOR_EVENT_DELETED,
filename,
NULL);
g_free (filename);
oldl = oldl->next;
}
else
{
filename = g_strconcat ("/", new->filename, NULL);
g_vfs_monitor_emit_event (backend->root_monitor,
G_FILE_MONITOR_EVENT_CREATED,
filename,
NULL);
g_free (filename);
newl = newl->next;
}
}
g_list_foreach (old_files, (GFunc)computer_file_free, NULL);
}
static void
recompute_files (GVfsBackendComputer *backend)
{
GVolumeMonitor *volume_monitor;
GList *drives, *volumes, *mounts, *l, *ll;
GDrive *drive;
GVolume *volume;
GMount *mount;
ComputerFile *file;
GList *files;
char *basename, *filename;
const char *extension;
int uniq;
gchar *s;
gchar *display_name;
gchar *drive_name;
volume_monitor = backend->volume_monitor;
files = NULL;
/* first go through all connected drives */
drives = g_volume_monitor_get_connected_drives (volume_monitor);
for (l = drives; l != NULL; l = l->next)
{
drive = l->data;
volumes = g_drive_get_volumes (drive);
if (volumes != NULL)
{
for (ll = volumes; ll != NULL; ll = ll->next)
{
volume = ll->data;
file = g_slice_new0 (ComputerFile);
file->drive = g_object_ref (drive);
file->volume = volume; /* Takes ref */
file->mount = g_volume_get_mount (volume);
file->prio = -3;
files = g_list_prepend (files, file);
}
g_list_free (volumes);
}
else
{
/* No volume, single drive */
file = g_slice_new0 (ComputerFile);
file->drive = g_object_ref (drive);
file->volume = NULL;
file->mount = NULL;
file->prio = -3;
files = g_list_prepend (files, file);
}
g_object_unref (drive);
}
g_list_free (drives);
/* add all volumes that is not associated with a drive */
volumes = g_volume_monitor_get_volumes (volume_monitor);
for (l = volumes; l != NULL; l = l->next)
{
volume = l->data;
drive = g_volume_get_drive (volume);
if (drive == NULL)
{
file = g_slice_new0 (ComputerFile);
file->drive = NULL;
file->volume = g_object_ref (volume);
file->mount = g_volume_get_mount (volume);
file->prio = -2;
files = g_list_prepend (files, file);
}
else
g_object_unref (drive);
g_object_unref (volume);
}
g_list_free (volumes);
/* add mounts that has no volume (/etc/mtab mounts, ftp, sftp,...) */
mounts = g_volume_monitor_get_mounts (volume_monitor);
for (l = mounts; l != NULL; l = l->next)
{
mount = l->data;
volume = g_mount_get_volume (mount);
if (volume == NULL && !g_mount_is_shadowed (mount))
{
file = g_slice_new0 (ComputerFile);
file->drive = NULL;
file->volume = NULL;
file->mount = g_object_ref (mount);
file->prio = -1;
files = g_list_prepend (files, file);
}
else
g_object_unref (volume);
g_object_unref (mount);
}
g_list_free (mounts);
files = g_list_reverse (files);
for (l = files; l != NULL; l = l->next)
{
file = l->data;
if (file->mount)
{
if (file->drive != NULL)
{
drive_name = g_drive_get_name (file->drive);
s = g_mount_get_name (file->mount);
display_name = g_strdup_printf ("%s: %s", drive_name, s);
g_free (s);
g_free (drive_name);
}
else
{
display_name = g_mount_get_name (file->mount);
}
if (file->volume != NULL)
file->unix_device_file = g_volume_get_identifier (file->volume,
G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
file->icon = g_mount_get_icon (file->mount);
file->symbolic_icon = g_mount_get_symbolic_icon (file->mount);
file->display_name = display_name;
file->root = g_mount_get_default_location (file->mount);
file->can_unmount = g_mount_can_unmount (file->mount);
file->can_eject = g_mount_can_eject (file->mount);
}
else if (file->volume)
{
if (file->drive != NULL)
{
drive_name = g_drive_get_name (file->drive);
s = g_volume_get_name (file->volume);
display_name = g_strdup_printf ("%s: %s", drive_name, s);
g_free (s);
g_free (drive_name);
}
else
{
display_name = g_volume_get_name (file->volume);
}
file->unix_device_file = g_volume_get_identifier (file->volume,
G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
file->icon = g_volume_get_icon (file->volume);
file->symbolic_icon = g_volume_get_symbolic_icon (file->volume);
file->display_name = display_name;
file->can_mount = g_volume_can_mount (file->volume);
file->root = NULL;
file->can_eject = g_volume_can_eject (file->volume);
}
else /* drive */
{
file->unix_device_file = g_drive_get_identifier (file->drive,
G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
file->icon = g_drive_get_icon (file->drive);
file->symbolic_icon = g_drive_get_symbolic_icon (file->drive);
file->display_name = g_drive_get_name (file->drive);
file->can_eject = g_drive_can_eject (file->drive);
file->can_mount = ! g_drive_is_media_removable (file->drive) || ! g_drive_is_media_check_automatic (file->drive) || g_drive_has_media (file->drive);
}
if (file->drive)
{
file->can_start = g_drive_can_start (file->drive);
file->can_start_degraded = g_drive_can_start_degraded (file->drive);
file->can_stop = g_drive_can_stop (file->drive);
file->can_poll_for_media = g_drive_can_poll_for_media (file->drive);
file->is_media_check_automatic = g_drive_is_media_check_automatic (file->drive);
file->start_stop_type = g_drive_get_start_stop_type (file->drive);
if (file->can_start)
file->can_mount = FALSE;
basename = g_drive_get_name (file->drive);
extension = ".drive";
}
else if (file->volume)
{
basename = g_volume_get_name (file->volume);
extension = ".volume";
}
else /* mount */
{
basename = g_mount_get_name (file->mount);
extension = ".mount";
}
convert_slashes (basename); /* No slashes in filenames */
uniq = 1;
filename = g_strconcat (basename, extension, NULL);
while (filename_is_used (files, filename))
{
g_free (filename);
filename = g_strdup_printf ("%s-%d%s",
basename,
uniq++,
extension);
}
g_free (basename);
file->filename = filename;
}
file = g_slice_new0 (ComputerFile);
file->filename = g_strdup ("root.link");
file->display_name = g_strdup (_("File System"));
file->icon = g_themed_icon_new_with_default_fallbacks ("drive-harddisk-system");
file->symbolic_icon = g_themed_icon_new_with_default_fallbacks ("drive-harddisk-system-symbolic");
file->root = g_file_new_for_path ("/");
file->prio = 0;
files = g_list_prepend (files, file);
files = g_list_sort (files, (GCompareFunc)sort_file_by_filename);
update_from_files (backend, files);
}
static gboolean
recompute_files_in_idle (GVfsBackendComputer *backend)
{
backend->recompute_idle_tag = 0;
recompute_files (backend);
return FALSE;
}
static void
object_changed (GVolumeMonitor *monitor,
gpointer object,
GVfsBackendComputer *backend)
{
if (backend->recompute_idle_tag == 0)
backend->recompute_idle_tag =
g_idle_add ((GSourceFunc)recompute_files_in_idle,
backend);
}
static gboolean
try_mount (GVfsBackend *backend,
GVfsJobMount *job,
GMountSpec *mount_spec,
GMountSource *mount_source,
gboolean is_automount)
{
GVfsBackendComputer *computer_backend = G_VFS_BACKEND_COMPUTER (backend);
int i;
char *signals[] = {
"volume-added",
"volume-removed",
"volume-changed",
"mount-added",
"mount-removed",
"mount-changed",
"drive-connected",
"drive-disconnected",
"drive-changed",
NULL
};
computer_backend->volume_monitor = g_volume_monitor_get ();
/* TODO: connect all signals to object_changed */
for (i = 0; signals[i] != NULL; i++)
g_signal_connect_data (computer_backend->volume_monitor,
signals[i],
(GCallback)object_changed,
backend,
NULL, 0);
computer_backend->root_monitor = g_vfs_monitor_new (backend);
recompute_files (computer_backend);
g_vfs_job_succeeded (G_VFS_JOB (job));
return TRUE;
}
static ComputerFile *
lookup (GVfsBackendComputer *backend,
GVfsJob *job,
const char *filename)
{
GList *l;
ComputerFile *file;
if (*filename != '/')
goto out;
while (*filename == '/')
filename++;
if (*filename == 0)
return &root;
if (strchr (filename, '/') != NULL)
goto out;
for (l = backend->files; l != NULL; l = l->next)
{
file = l->data;
if (strcmp (file->filename, filename) == 0)
return file;
}
out:
g_vfs_job_failed (job, G_IO_ERROR,
G_IO_ERROR_NOT_FOUND,
_("File doesnt exist"));
return NULL;
}
static gboolean
try_open_for_read (GVfsBackend *backend,
GVfsJobOpenForRead *job,
const char *filename)
{
ComputerFile *file;
file = lookup (G_VFS_BACKEND_COMPUTER (backend),
G_VFS_JOB (job), filename);
if (file == &root)
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
G_IO_ERROR_IS_DIRECTORY,
_("Cant open directory"));
else if (file != NULL)
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
_("Cant open mountable file"));
return TRUE;
}
static void
file_info_from_file (ComputerFile *file,
GFileInfo *info)
{
char *uri;
g_file_info_set_name (info, file->filename);
g_file_info_set_display_name (info, file->display_name);
if (file->icon)
g_file_info_set_icon (info, file->icon);
if (file->symbolic_icon)
g_file_info_set_symbolic_icon (info, file->symbolic_icon);
if (file->root)
{
uri = g_file_get_uri (file->root);
g_file_info_set_attribute_string (info,
G_FILE_ATTRIBUTE_STANDARD_TARGET_URI,
uri);
g_free (uri);
}
g_file_info_set_sort_order (info, file->prio);
g_file_info_set_file_type (info, G_FILE_TYPE_MOUNTABLE);
if (file->unix_device_file != NULL)
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_MOUNTABLE_UNIX_DEVICE_FILE, file->unix_device_file);
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_MOUNT, file->can_mount);
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_UNMOUNT, file->can_unmount);
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_EJECT, file->can_eject);
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_START, file->can_start);
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_START_DEGRADED, file->can_start_degraded);
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_STOP, file->can_stop);
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_POLL, file->can_poll_for_media);
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_MOUNTABLE_IS_MEDIA_CHECK_AUTOMATIC, file->is_media_check_automatic);
g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_MOUNTABLE_START_STOP_TYPE, file->start_stop_type);
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE, FALSE);
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME, FALSE);
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE, FALSE);
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH, FALSE);
}
static gboolean
try_enumerate (GVfsBackend *backend,
GVfsJobEnumerate *job,
const char *filename,
GFileAttributeMatcher *attribute_matcher,
GFileQueryInfoFlags flags)
{
ComputerFile *file;
GList *l;
GFileInfo *info;
file = lookup (G_VFS_BACKEND_COMPUTER (backend),
G_VFS_JOB (job), filename);
if (file != &root)
{
if (file != NULL)
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
G_IO_ERROR_NOT_DIRECTORY,
_("The file is not a directory"));
return TRUE;
}
g_vfs_job_succeeded (G_VFS_JOB (job));
/* Enumerate root */
for (l = G_VFS_BACKEND_COMPUTER (backend)->files; l != NULL; l = l->next)
{
file = l->data;
info = g_file_info_new ();
file_info_from_file (file, info);
g_vfs_job_enumerate_add_info (job, info);
g_object_unref (info);
}
g_vfs_job_enumerate_done (job);
return TRUE;
}
static gboolean
try_query_info (GVfsBackend *backend,
GVfsJobQueryInfo *job,
const char *filename,
GFileQueryInfoFlags flags,
GFileInfo *info,
GFileAttributeMatcher *matcher)
{
ComputerFile *file;
file = lookup (G_VFS_BACKEND_COMPUTER (backend),
G_VFS_JOB (job), filename);
if (file == &root)
{
GIcon *icon;
g_file_info_set_name (info, "/");
g_file_info_set_file_type (info, G_FILE_TYPE_DIRECTORY);
g_file_info_set_display_name (info, _("Computer"));
icon = g_themed_icon_new ("computer");
g_file_info_set_icon (info, icon);
g_object_unref (icon);
icon = g_themed_icon_new ("computer-symbolic");
g_file_info_set_symbolic_icon (info, icon);
g_object_unref (icon);
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE, FALSE);
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE, FALSE);
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH, FALSE);
g_file_info_set_content_type (info, "inode/directory");
g_vfs_job_succeeded (G_VFS_JOB (job));
}
else if (file != NULL)
{
file_info_from_file (file, info);
g_vfs_job_succeeded (G_VFS_JOB (job));
}
return TRUE;
}
static gboolean
try_create_dir_monitor (GVfsBackend *backend,
GVfsJobCreateMonitor *job,
const char *filename,
GFileMonitorFlags flags)
{
ComputerFile *file;
GVfsBackendComputer *computer_backend;
computer_backend = G_VFS_BACKEND_COMPUTER (backend);
file = lookup (computer_backend,
G_VFS_JOB (job), filename);
if (file != &root)
{
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
_("Operation not supported"));
return TRUE;
}
g_vfs_job_create_monitor_set_monitor (job,
computer_backend->root_monitor);
g_vfs_job_succeeded (G_VFS_JOB (job));
return TRUE;
}
static void
mount_volume_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
GVfsJobMountMountable *job = user_data;
GError *error;
GMount *mount;
GVolume *volume;
GFile *root;
char *uri;
volume = G_VOLUME (source_object);
error = NULL;
if (g_volume_mount_finish (volume, res, &error))
{
mount = g_volume_get_mount (volume);
if (mount)
{
root = g_mount_get_root (mount);
uri = g_file_get_uri (root);
g_vfs_job_mount_mountable_set_target_uri (job,
uri,
FALSE);
g_free (uri);
g_object_unref (root);
g_object_unref (mount);
g_vfs_job_succeeded (G_VFS_JOB (job));
}
else
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
G_IO_ERROR_FAILED,
_("Internal error: %s"), "No mount object for mounted volume");
}
else
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
g_error_free (error);
}
}
static void
mount_volume_from_drive (GDrive *drive,
GVfsJob *job,
GMountOperation *mount_op)
{
GList *volumes;
GVolume *volume;
volumes = g_drive_get_volumes (drive);
if (volumes)
{
volume = G_VOLUME (volumes->data);
g_volume_mount (volume,
0,
mount_op,
G_VFS_JOB (job)->cancellable,
mount_volume_cb,
job);
}
else
{
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
_("Cant mount file"));
}
g_list_free_full (volumes, g_object_unref);
}
static void
report_no_media_error (GVfsJob *job)
{
g_vfs_job_failed (job, G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
_("No medium in the drive"));
}
typedef struct {
GVfsJobMountMountable *job;
GMountOperation *mount_op;
} PollForMediaData;
static void
poll_for_media_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
PollForMediaData *data = user_data;
GDrive *drive;
GError *error;
drive = G_DRIVE (source_object);
error = NULL;
if (g_drive_poll_for_media_finish (drive, res, &error))
{
gboolean has_media;
has_media = g_drive_has_media (drive);
if (!has_media)
{
report_no_media_error (G_VFS_JOB (data->job));
}
else
{
mount_volume_from_drive (drive, G_VFS_JOB (data->job), data->mount_op);
g_slice_free (PollForMediaData, data);
}
}
else
{
g_vfs_job_failed_from_error (G_VFS_JOB (data->job), error);
g_error_free (error);
}
}
static gboolean
try_mount_mountable (GVfsBackend *backend,
GVfsJobMountMountable *job,
const char *filename,
GMountSource *mount_source)
{
ComputerFile *file;
GMountOperation *mount_op;
file = lookup (G_VFS_BACKEND_COMPUTER (backend),
G_VFS_JOB (job), filename);
if (file == &root)
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
G_IO_ERROR_NOT_MOUNTABLE_FILE,
_("Not a mountable file"));
else if (file != NULL)
{
if (file->volume)
{
mount_op = g_mount_source_get_operation (mount_source);
/* free mount_op when job is completed */
g_object_set_data_full (G_OBJECT (job), "gvfs-backend-computer-mount-op", mount_op, g_object_unref);
g_volume_mount (file->volume,
0,
mount_op,
G_VFS_JOB (job)->cancellable,
mount_volume_cb,
job);
}
else if (file->drive)
{
if (!g_drive_has_media (file->drive))
{
if (!g_drive_can_poll_for_media (file->drive))
report_no_media_error (G_VFS_JOB (job));
else
{
PollForMediaData *data;
data = g_slice_new0 (PollForMediaData);
mount_op = g_mount_source_get_operation (mount_source);
data->job = job;
data->mount_op = mount_op;
if (!g_drive_is_media_check_automatic (file->drive))
g_drive_poll_for_media (file->drive,
G_VFS_JOB (job)->cancellable,
poll_for_media_cb,
data);
else
report_no_media_error (G_VFS_JOB (job));
}
}
else
{
mount_op = g_mount_source_get_operation (mount_source);
mount_volume_from_drive (file->drive, G_VFS_JOB (job), mount_op);
}
}
else
{
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
_("Cant mount file"));
}
}
return TRUE;
}
static void
unmount_mount_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
GVfsJobMountMountable *job = user_data;
GError *error;
GMount *mount;
mount = G_MOUNT (source_object);
error = NULL;
if (g_mount_unmount_with_operation_finish (mount, res, &error))
g_vfs_job_succeeded (G_VFS_JOB (job));
else
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
g_error_free (error);
}
}
static gboolean
try_unmount_mountable (GVfsBackend *backend,
GVfsJobUnmountMountable *job,
const char *filename,
GMountUnmountFlags flags,
GMountSource *mount_source)
{
ComputerFile *file;
GMountOperation *mount_op;
file = lookup (G_VFS_BACKEND_COMPUTER (backend),
G_VFS_JOB (job), filename);
if (file == &root)
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
G_IO_ERROR_NOT_MOUNTABLE_FILE,
_("Not a mountable file"));
else if (file != NULL)
{
if (file->mount)
{
mount_op = g_mount_source_get_operation (mount_source);
/* free mount_op when job is completed */
g_object_set_data_full (G_OBJECT (job), "gvfs-backend-computer-mount-op", mount_op, g_object_unref);
g_mount_unmount_with_operation (file->mount,
flags,
mount_op,
G_VFS_JOB (job)->cancellable,
unmount_mount_cb,
job);
}
else
{
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
_("Cant unmount file"));
}
}
return TRUE;
}
static void
eject_mount_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
GVfsJobMountMountable *job = user_data;
GError *error;
GMount *mount;
mount = G_MOUNT (source_object);
error = NULL;
if (g_mount_eject_with_operation_finish (mount, res, &error))
g_vfs_job_succeeded (G_VFS_JOB (job));
else
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
g_error_free (error);
}
}
static void
eject_volume_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
GVfsJobMountMountable *job = user_data;
GError *error;
GVolume *volume;
volume = G_VOLUME (source_object);
error = NULL;
if (g_volume_eject_with_operation_finish (volume, res, &error))
g_vfs_job_succeeded (G_VFS_JOB (job));
else
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
g_error_free (error);
}
}
static void
eject_drive_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
GVfsJobMountMountable *job = user_data;
GError *error;
GDrive *drive;
drive = G_DRIVE (source_object);
error = NULL;
if (g_drive_eject_with_operation_finish (drive, res, &error))
g_vfs_job_succeeded (G_VFS_JOB (job));
else
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
g_error_free (error);
}
}
static gboolean
try_eject_mountable (GVfsBackend *backend,
GVfsJobUnmountMountable *job,
const char *filename,
GMountUnmountFlags flags,
GMountSource *mount_source)
{
ComputerFile *file;
GMountOperation *mount_op;
file = lookup (G_VFS_BACKEND_COMPUTER (backend),
G_VFS_JOB (job), filename);
if (file == &root)
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
G_IO_ERROR_NOT_MOUNTABLE_FILE,
_("Not a mountable file"));
else if (file != NULL)
{
if (file->mount)
{
mount_op = g_mount_source_get_operation (mount_source);
/* free mount_op when job is completed */
g_object_set_data_full (G_OBJECT (job), "gvfs-backend-computer-mount-op", mount_op, g_object_unref);
g_mount_eject_with_operation (file->mount,
flags,
mount_op,
G_VFS_JOB (job)->cancellable,
eject_mount_cb,
job);
}
else if (file->volume)
{
mount_op = g_mount_source_get_operation (mount_source);
/* free mount_op when job is completed */
g_object_set_data_full (G_OBJECT (job), "gvfs-backend-computer-mount-op", mount_op, g_object_unref);
g_volume_eject_with_operation (file->volume,
flags,
mount_op,
G_VFS_JOB (job)->cancellable,
eject_volume_cb,
job);
}
else if (file->drive)
{
mount_op = g_mount_source_get_operation (mount_source);
/* free mount_op when job is completed */
g_object_set_data_full (G_OBJECT (job), "gvfs-backend-computer-mount-op", mount_op, g_object_unref);
g_drive_eject_with_operation (file->drive,
flags,
mount_op,
G_VFS_JOB (job)->cancellable,
eject_drive_cb,
job);
}
else
{
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
_("Cant eject file"));
}
}
return TRUE;
}
static void
drive_start_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
GVfsJobStartMountable *job = user_data;
GError *error;
GDrive *drive;
drive = G_DRIVE (source_object);
error = NULL;
if (g_drive_start_finish (drive, res, &error))
{
g_vfs_job_succeeded (G_VFS_JOB (job));
}
else
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
g_error_free (error);
}
}
static gboolean
try_start_mountable (GVfsBackend *backend,
GVfsJobStartMountable *job,
const char *filename,
GMountSource *mount_source)
{
ComputerFile *file;
GMountOperation *mount_op;
file = lookup (G_VFS_BACKEND_COMPUTER (backend),
G_VFS_JOB (job), filename);
if (file == &root)
{
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
G_IO_ERROR_NOT_MOUNTABLE_FILE,
_("Not a mountable file"));
}
else if (file != NULL)
{
if (file->drive != NULL)
{
mount_op = g_mount_source_get_operation (mount_source);
/* free mount_op when job is completed */
g_object_set_data_full (G_OBJECT (job), "gvfs-backend-computer-start-op", mount_op, g_object_unref);
g_drive_start (file->drive,
0,
mount_op,
G_VFS_JOB (job)->cancellable,
drive_start_cb,
job);
}
else
{
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
_("Cant start drive"));
}
}
else
{
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
_("Cant start drive"));
}
return TRUE;
}
static void
drive_stop_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
GVfsJobStopMountable *job = user_data;
GError *error;
GDrive *drive;
drive = G_DRIVE (source_object);
error = NULL;
if (g_drive_stop_finish (drive, res, &error))
{
g_vfs_job_succeeded (G_VFS_JOB (job));
}
else
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
g_error_free (error);
}
}
static gboolean
try_stop_mountable (GVfsBackend *backend,
GVfsJobStopMountable *job,
const char *filename,
GMountUnmountFlags flags,
GMountSource *mount_source)
{
ComputerFile *file;
GMountOperation *mount_op;
file = lookup (G_VFS_BACKEND_COMPUTER (backend),
G_VFS_JOB (job), filename);
if (file == &root)
{
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
G_IO_ERROR_NOT_MOUNTABLE_FILE,
_("Not a mountable file"));
}
else if (file != NULL)
{
if (file->drive != NULL)
{
mount_op = g_mount_source_get_operation (mount_source);
/* free mount_op when job is completed */
g_object_set_data_full (G_OBJECT (job), "gvfs-backend-computer-start-op", mount_op, g_object_unref);
g_drive_stop (file->drive,
flags,
mount_op,
G_VFS_JOB (job)->cancellable,
drive_stop_cb,
job);
}
else
{
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
_("Cant stop drive"));
}
}
else
{
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
_("Cant stop drive"));
}
return TRUE;
}
static void
drive_poll_for_media_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
GVfsJobPollMountable *job = user_data;
GError *error;
GDrive *drive;
drive = G_DRIVE (source_object);
error = NULL;
if (g_drive_poll_for_media_finish (drive, res, &error))
{
g_vfs_job_succeeded (G_VFS_JOB (job));
}
else
{
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
g_error_free (error);
}
}
static gboolean
try_poll_mountable (GVfsBackend *backend,
GVfsJobPollMountable *job,
const char *filename)
{
ComputerFile *file;
file = lookup (G_VFS_BACKEND_COMPUTER (backend),
G_VFS_JOB (job), filename);
if (file == &root)
{
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
G_IO_ERROR_NOT_MOUNTABLE_FILE,
_("Not a mountable file"));
}
else if (file != NULL)
{
if (file->drive != NULL)
{
g_drive_poll_for_media (file->drive,
G_VFS_JOB (job)->cancellable,
drive_poll_for_media_cb,
job);
}
else
{
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
_("Cant poll file"));
}
}
else
{
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
_("Cant poll file"));
}
return TRUE;
}
static gboolean
try_query_fs_info (GVfsBackend *backend,
GVfsJobQueryFsInfo *job,
const char *filename,
GFileInfo *info,
GFileAttributeMatcher *matcher)
{
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "computer");
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, FALSE);
g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW, G_FILESYSTEM_PREVIEW_TYPE_NEVER);
g_vfs_job_succeeded (G_VFS_JOB (job));
return TRUE;
}
static void
g_vfs_backend_computer_class_init (GVfsBackendComputerClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GVfsBackendClass *backend_class = G_VFS_BACKEND_CLASS (klass);
gobject_class->finalize = g_vfs_backend_computer_finalize;
backend_class->try_mount = try_mount;
backend_class->try_open_for_read = try_open_for_read;
backend_class->try_query_info = try_query_info;
backend_class->try_query_fs_info = try_query_fs_info;
backend_class->try_enumerate = try_enumerate;
backend_class->try_create_dir_monitor = try_create_dir_monitor;
backend_class->try_mount_mountable = try_mount_mountable;
backend_class->try_unmount_mountable = try_unmount_mountable;
backend_class->try_eject_mountable = try_eject_mountable;
backend_class->try_start_mountable = try_start_mountable;
backend_class->try_stop_mountable = try_stop_mountable;
backend_class->try_poll_mountable = try_poll_mountable;
}