From 32d84ada85484e9317ab3108e7af4e81695a648c Mon Sep 17 00:00:00 2001 From: Tomas Bzatek Date: Mon, 22 Jun 2009 12:40:51 +0000 Subject: [PATCH] - Bump version requirements - Backport FTP and Computer backend patches from master --- ...pare-the-code-for-active-FTP-support.patch | 205 + ...e-able-to-connect-to-an-Active-FTP-S.patch | 361 ++ ...-the-error-code-for-EPRT-s-522-error.patch | 27 + 0005-FTP-add-EPRT-support.patch | 101 + ...-computer-crashes-with-SEGSEV-in-rec.patch | 36 + ...-Better-handling-of-PC-floppy-drives.patch | 117 + ...-feature-response-for-EPRT-support-n.patch | 51 + 0009-FTP-remove-EPSV-as-default-feature.patch | 27 + 0014-gvfs-use-device-media-detected.patch | 59 - ...respect-presentation-hide-for-drives.patch | 29 - gdu-0001-Bug-573826-gdu-volume-monitor.patch | 5250 ----------------- ...-we-determine-if-a-volume-is-ignored.patch | 69 - ...ng-volumes-on-virtual-and-unknown-bu.patch | 87 - gdu-0004-Remove-debug-spew.patch | 27 - ...me-if-the-device-is-mounted-and-igno.patch | 31 - ...-all-volumes-of-the-drive-are-ignore.patch | 41 - ...llow-eject-even-on-non-ejectable-vol.patch | 49 - gdu-0008-ignore-drives-without-volumes.patch | 41 - ...09-never-ignore-drives-without-media.patch | 73 - ...10-show-user-mountable-fstab-entries.patch | 876 --- ...re-unmount-signals-not-being-trigger.patch | 326 - ...sk-utility-API-to-hide-unwanted-devi.patch | 52 - ...pass-the-flush-mount-option-for-vfat.patch | 99 - ...low-query-well-formed-filenames-only.patch | 32 - gvfs.spec | 33 +- 25 files changed, 954 insertions(+), 7145 deletions(-) create mode 100644 0001-FTP-prepare-the-code-for-active-FTP-support.patch create mode 100644 0002-FTP-Bug-516704-Be-able-to-connect-to-an-Active-FTP-S.patch create mode 100644 0004-FTP-add-the-error-code-for-EPRT-s-522-error.patch create mode 100644 0005-FTP-add-EPRT-support.patch create mode 100644 0006-Bug-582772-gvfsd-computer-crashes-with-SEGSEV-in-rec.patch create mode 100644 0007-Better-handling-of-PC-floppy-drives.patch create mode 100644 0008-FTP-use-the-EPRT-feature-response-for-EPRT-support-n.patch create mode 100644 0009-FTP-remove-EPSV-as-default-feature.patch delete mode 100644 0014-gvfs-use-device-media-detected.patch delete mode 100644 0015-gvfs-respect-presentation-hide-for-drives.patch delete mode 100644 gdu-0001-Bug-573826-gdu-volume-monitor.patch delete mode 100644 gdu-0002-Fix-how-we-determine-if-a-volume-is-ignored.patch delete mode 100644 gdu-0003-Avoid-automounting-volumes-on-virtual-and-unknown-bu.patch delete mode 100644 gdu-0004-Remove-debug-spew.patch delete mode 100644 gdu-0005-Don-t-add-a-volume-if-the-device-is-mounted-and-igno.patch delete mode 100644 gdu-0006-Ignore-drives-if-all-volumes-of-the-drive-are-ignore.patch delete mode 100644 gdu-0007-Bug-576587-allow-eject-even-on-non-ejectable-vol.patch delete mode 100644 gdu-0008-ignore-drives-without-volumes.patch delete mode 100644 gdu-0009-never-ignore-drives-without-media.patch delete mode 100644 gdu-0010-show-user-mountable-fstab-entries.patch delete mode 100644 gdu-0011-Bug-576083-pre-unmount-signals-not-being-trigger.patch delete mode 100644 gdu-0012-use-new-gnome-disk-utility-API-to-hide-unwanted-devi.patch delete mode 100644 gdu-0013-pass-the-flush-mount-option-for-vfat.patch delete mode 100644 gvfs-1.2.3-cdda-allow-query-well-formed-filenames-only.patch diff --git a/0001-FTP-prepare-the-code-for-active-FTP-support.patch b/0001-FTP-prepare-the-code-for-active-FTP-support.patch new file mode 100644 index 0000000..c3a99de --- /dev/null +++ b/0001-FTP-prepare-the-code-for-active-FTP-support.patch @@ -0,0 +1,205 @@ +From 7f2ac23d150aa779310a37534fc8564bbfc93b86 Mon Sep 17 00:00:00 2001 +From: Benjamin Otte +Date: Mon, 15 Jun 2009 22:02:34 +0200 +Subject: [PATCH 01/13] [FTP] prepare the code for active FTP support + +adds a bunch of new APIs necessary for supporting active FTP. These APIs +don't do anything yet, as active FTP is still unsupported, it's just +refactoring of code. +--- + daemon/gvfsbackendftp.c | 11 +++++++-- + daemon/gvfsftpdircache.c | 4 +- + daemon/gvfsftptask.c | 47 ++++++++++++++++++++++++++++++++------------- + daemon/gvfsftptask.h | 1 + + 4 files changed, 44 insertions(+), 19 deletions(-) + +diff --git a/daemon/gvfsbackendftp.c b/daemon/gvfsbackendftp.c +index ba6acd4..913eb1c 100644 +--- a/daemon/gvfsbackendftp.c ++++ b/daemon/gvfsbackendftp.c +@@ -642,7 +642,7 @@ do_open_for_read (GVfsBackend *backend, + error_550_permission_or_not_found, + NULL }; + +- g_vfs_ftp_task_open_data_connection (&task); ++ g_vfs_ftp_task_setup_data_connection (&task); + file = g_vfs_ftp_file_new_from_gvfs (ftp, filename); + + g_vfs_ftp_task_send_and_check (&task, +@@ -653,6 +653,8 @@ do_open_for_read (GVfsBackend *backend, + "RETR %s", g_vfs_ftp_file_get_ftp_path (file)); + g_vfs_ftp_file_free (file); + ++ g_vfs_ftp_task_open_data_connection (&task); ++ + if (!g_vfs_ftp_task_is_in_error (&task)) + { + /* don't push the connection back, it's our handle now */ +@@ -722,7 +724,7 @@ do_start_write (GVfsFtpTask *task, + + /* FIXME: can we honour the flags? */ + +- g_vfs_ftp_task_open_data_connection (task); ++ g_vfs_ftp_task_setup_data_connection (task); + + va_start (varargs, format); + g_vfs_ftp_task_sendv (task, +@@ -732,6 +734,8 @@ do_start_write (GVfsFtpTask *task, + varargs); + va_end (varargs); + ++ g_vfs_ftp_task_open_data_connection (task); ++ + if (!g_vfs_ftp_task_is_in_error (task)) + { + /* don't push the connection back, it's our handle now */ +@@ -1280,13 +1284,14 @@ do_pull (GVfsBackend * backend, + } + else + total_size = 0; +- g_vfs_ftp_task_open_data_connection (&task); ++ g_vfs_ftp_task_setup_data_connection (&task); + g_vfs_ftp_task_send_and_check (&task, + G_VFS_FTP_PASS_100 | G_VFS_FTP_FAIL_200, + &open_read_handlers[0], + src, + NULL, + "RETR %s", g_vfs_ftp_file_get_ftp_path (src)); ++ g_vfs_ftp_task_open_data_connection (&task); + if (g_vfs_ftp_task_is_in_error (&task)) + { + g_vfs_ftp_file_free (src); +diff --git a/daemon/gvfsftpdircache.c b/daemon/gvfsftpdircache.c +index 26984f4..8e6de25 100644 +--- a/daemon/gvfsftpdircache.c ++++ b/daemon/gvfsftpdircache.c +@@ -153,11 +153,11 @@ g_vfs_ftp_dir_cache_lookup_entry (GVfsFtpDirCache * cache, + G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY, + _("The file is not a directory")); + } +- g_vfs_ftp_task_open_data_connection (task); +- ++ g_vfs_ftp_task_setup_data_connection (task); + g_vfs_ftp_task_send (task, + G_VFS_FTP_PASS_100 | G_VFS_FTP_FAIL_200, + "%s", cache->funcs->command); ++ g_vfs_ftp_task_open_data_connection (task); + if (g_vfs_ftp_task_is_in_error (task)) + return NULL; + +diff --git a/daemon/gvfsftptask.c b/daemon/gvfsftptask.c +index 118f80d..37f2b59 100644 +--- a/daemon/gvfsftptask.c ++++ b/daemon/gvfsftptask.c +@@ -747,7 +747,7 @@ g_vfs_ftp_task_create_remote_address (GVfsFtpTask *task, guint port) + } + + static GVfsFtpMethod +-g_vfs_ftp_task_open_data_connection_epsv (GVfsFtpTask *task, GVfsFtpMethod method) ++g_vfs_ftp_task_setup_data_connection_epsv (GVfsFtpTask *task, GVfsFtpMethod method) + { + const char *s; + char **reply; +@@ -790,7 +790,7 @@ fail: + } + + static GVfsFtpMethod +-g_vfs_ftp_task_open_data_connection_pasv (GVfsFtpTask *task, GVfsFtpMethod method) ++g_vfs_ftp_task_setup_data_connection_pasv (GVfsFtpTask *task, GVfsFtpMethod method) + { + guint ip1, ip2, ip3, ip4, port1, port2; + char **reply; +@@ -875,14 +875,14 @@ g_vfs_ftp_task_open_data_connection_pasv (GVfsFtpTask *task, GVfsFtpMethod metho + typedef GVfsFtpMethod (* GVfsFtpOpenDataConnectionFunc) (GVfsFtpTask *task, GVfsFtpMethod method); + + static GVfsFtpMethod +-g_vfs_ftp_task_open_data_connection_any (GVfsFtpTask *task, GVfsFtpMethod unused) ++g_vfs_ftp_task_setup_data_connection_any (GVfsFtpTask *task, GVfsFtpMethod unused) + { + static const struct { + GVfsFtpFeature required_feature; + GVfsFtpOpenDataConnectionFunc func; + } funcs_ordered[] = { +- { G_VFS_FTP_FEATURE_EPSV, g_vfs_ftp_task_open_data_connection_epsv }, +- { 0, g_vfs_ftp_task_open_data_connection_pasv } ++ { G_VFS_FTP_FEATURE_EPSV, g_vfs_ftp_task_setup_data_connection_epsv }, ++ { 0, g_vfs_ftp_task_setup_data_connection_pasv } + }; + GVfsFtpMethod method; + guint i; +@@ -918,20 +918,23 @@ g_vfs_ftp_task_open_data_connection_any (GVfsFtpTask *task, GVfsFtpMethod unused + } + + /** +- * g_vfs_ftp_task_open_data_connection: ++ * g_vfs_ftp_task_setup_data_connection: + * @task: a task not having an open data connection + * +- * Tries to open a data connection to the ftp server. If the operation fails, +- * @task will be set into an error state. ++ * Sets up a data connection to the ftp server with using the best method for ++ * this task. If the operation fails, @task will be set into an error state. ++ * You must call g_vfs_ftp_task_open_data_connection() to finish setup and ++ * ensure the data connection actually gets opened. Usually, this requires ++ * sending an FTP command down the stream. + **/ + void +-g_vfs_ftp_task_open_data_connection (GVfsFtpTask *task) ++g_vfs_ftp_task_setup_data_connection (GVfsFtpTask *task) + { + static const GVfsFtpOpenDataConnectionFunc connect_funcs[] = { +- [G_VFS_FTP_METHOD_ANY] = g_vfs_ftp_task_open_data_connection_any, +- [G_VFS_FTP_METHOD_EPSV] = g_vfs_ftp_task_open_data_connection_epsv, +- [G_VFS_FTP_METHOD_PASV] = g_vfs_ftp_task_open_data_connection_pasv, +- [G_VFS_FTP_METHOD_PASV_ADDR] = g_vfs_ftp_task_open_data_connection_pasv, ++ [G_VFS_FTP_METHOD_ANY] = g_vfs_ftp_task_setup_data_connection_any, ++ [G_VFS_FTP_METHOD_EPSV] = g_vfs_ftp_task_setup_data_connection_epsv, ++ [G_VFS_FTP_METHOD_PASV] = g_vfs_ftp_task_setup_data_connection_pasv, ++ [G_VFS_FTP_METHOD_PASV_ADDR] = g_vfs_ftp_task_setup_data_connection_pasv, + [G_VFS_FTP_METHOD_EPRT] = NULL, + [G_VFS_FTP_METHOD_PORT] = NULL + }; +@@ -953,7 +956,7 @@ g_vfs_ftp_task_open_data_connection (GVfsFtpTask *task) + if (result == G_VFS_FTP_METHOD_ANY && + method != G_VFS_FTP_METHOD_ANY && + !g_vfs_ftp_task_is_in_error (task)) +- result = g_vfs_ftp_task_open_data_connection_any (task, G_VFS_FTP_METHOD_ANY); ++ result = g_vfs_ftp_task_setup_data_connection_any (task, G_VFS_FTP_METHOD_ANY); + + g_assert (result < G_N_ELEMENTS (connect_funcs) && connect_funcs[result]); + if (result != method) +@@ -972,3 +975,19 @@ g_vfs_ftp_task_open_data_connection (GVfsFtpTask *task) + } + } + ++/** ++ * g_vfs_ftp_task_open_data_connection: ++ * @task: a task ++ * ++ * Tries to open a data connection to the ftp server. If the operation fails, ++ * @task will be set into an error state. ++ **/ ++void ++g_vfs_ftp_task_open_data_connection (GVfsFtpTask *task) ++{ ++ g_return_if_fail (task != NULL); ++ ++ if (g_vfs_ftp_task_is_in_error (task)) ++ return; ++} ++ +diff --git a/daemon/gvfsftptask.h b/daemon/gvfsftptask.h +index 6453f41..8345535 100644 +--- a/daemon/gvfsftptask.h ++++ b/daemon/gvfsftptask.h +@@ -82,6 +82,7 @@ guint g_vfs_ftp_task_sendv (GVfsFtpTask * + guint g_vfs_ftp_task_receive (GVfsFtpTask * task, + GVfsFtpResponseFlags flags, + char *** reply); ++void g_vfs_ftp_task_setup_data_connection (GVfsFtpTask * task); + void g_vfs_ftp_task_open_data_connection (GVfsFtpTask * task); + void g_vfs_ftp_task_close_data_connection (GVfsFtpTask * task); + +-- +1.6.3.2 + diff --git a/0002-FTP-Bug-516704-Be-able-to-connect-to-an-Active-FTP-S.patch b/0002-FTP-Bug-516704-Be-able-to-connect-to-an-Active-FTP-S.patch new file mode 100644 index 0000000..195dd9e --- /dev/null +++ b/0002-FTP-Bug-516704-Be-able-to-connect-to-an-Active-FTP-S.patch @@ -0,0 +1,361 @@ +From 2839922c259b848d7689d245a055c628754dc116 Mon Sep 17 00:00:00 2001 +From: Benjamin Otte +Date: Mon, 15 Jun 2009 23:03:26 +0200 +Subject: [PATCH 02/13] =?utf-8?q?[FTP]=20Bug=20516704=20=E2=80=93=20Be=20able=20to=20connect=20to=20an=20Active=20FTP=20Site?= +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: 8bit + +Add initial support for the PORT command. Support for EPRT and a +non-ugly API are still missing. +--- + daemon/gvfsftpconnection.c | 157 +++++++++++++++++++++++++++++++++++++++++++- + daemon/gvfsftpconnection.h | 7 ++ + daemon/gvfsftptask.c | 56 ++++++++++++++-- + daemon/gvfsftptask.h | 1 + + 4 files changed, 215 insertions(+), 6 deletions(-) + +diff --git a/daemon/gvfsftpconnection.c b/daemon/gvfsftpconnection.c +index ac5418f..521664c 100644 +--- a/daemon/gvfsftpconnection.c ++++ b/daemon/gvfsftpconnection.c +@@ -22,10 +22,12 @@ + + #include + ++#include "gvfsftpconnection.h" ++ + #include + #include + +-#include "gvfsftpconnection.h" ++#include "gvfsbackendftp.h" + + /* used for identifying the connection during debugging */ + static volatile int debug_id = 0; +@@ -37,6 +39,7 @@ struct _GVfsFtpConnection + GIOStream * commands; /* ftp command stream */ + GDataInputStream * commands_in; /* wrapper around in stream to allow line-wise reading */ + ++ GSocket * listen_socket; /* socket we are listening on for active FTP connections */ + GIOStream * data; /* ftp data stream or NULL if not in use */ + + int debug_id; /* unique id for debugging purposes */ +@@ -71,11 +74,22 @@ g_vfs_ftp_connection_new (GSocketConnectable *addr, + return conn; + } + ++static void ++g_vfs_ftp_connection_stop_listening (GVfsFtpConnection *conn) ++{ ++ if (conn->listen_socket) ++ { ++ g_object_unref (conn->listen_socket); ++ conn->listen_socket = NULL; ++ } ++} ++ + void + g_vfs_ftp_connection_free (GVfsFtpConnection *conn) + { + g_return_if_fail (conn != NULL); + ++ g_vfs_ftp_connection_stop_listening (conn); + if (conn->data) + g_vfs_ftp_connection_close_data_connection (conn); + +@@ -218,6 +232,8 @@ g_vfs_ftp_connection_open_data_connection (GVfsFtpConnection *conn, + g_return_val_if_fail (conn != NULL, FALSE); + g_return_val_if_fail (conn->data == NULL, FALSE); + ++ g_vfs_ftp_connection_stop_listening (conn); ++ + conn->data = G_IO_STREAM (g_socket_client_connect (conn->client, + G_SOCKET_CONNECTABLE (addr), + cancellable, +@@ -226,6 +242,145 @@ g_vfs_ftp_connection_open_data_connection (GVfsFtpConnection *conn, + return conn->data != NULL; + } + ++/** ++ * g_vfs_ftp_connection_listen_data_connection: ++ * @conn: a connection ++ * @error: %NULL or location to take potential errors ++ * ++ * Initiates a listening socket that the FTP server can connect to. To accept ++ * connections and initialize data transfers, use ++ * g_vfs_ftp_connection_accept_data_connection(). ++ * This function supports what is known as "active FTP", while ++ * g_vfs_ftp_connection_open_data_connection() is to be used for "passive FTP". ++ * ++ * Returns: the actual address the socket is listening on or %NULL on error ++ **/ ++GSocketAddress * ++g_vfs_ftp_connection_listen_data_connection (GVfsFtpConnection *conn, ++ GError ** error) ++{ ++ GSocketAddress *local, *addr; ++ ++ g_return_val_if_fail (conn != NULL, NULL); ++ g_return_val_if_fail (conn->data == NULL, FALSE); ++ ++ g_vfs_ftp_connection_stop_listening (conn); ++ ++ local = g_socket_connection_get_local_address (G_SOCKET_CONNECTION (conn->commands), error); ++ if (local == NULL) ++ return NULL; ++ ++ conn->listen_socket = g_socket_new (g_socket_address_get_family (local), ++ G_SOCKET_TYPE_STREAM, ++ G_SOCKET_PROTOCOL_TCP, ++ error); ++ if (conn->listen_socket == NULL) ++ return NULL; ++ ++ g_assert (G_IS_INET_SOCKET_ADDRESS (local)); ++ addr = g_inet_socket_address_new (g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (local)), 0); ++ g_object_unref (local); ++ ++ if (!g_socket_bind (conn->listen_socket, addr, TRUE, error) || ++ !g_socket_listen (conn->listen_socket, error) || ++ !(local = g_socket_get_local_address (conn->listen_socket, error))) ++ { ++ g_object_unref (addr); ++ g_vfs_ftp_connection_stop_listening (conn); ++ return NULL; ++ } ++ ++ g_object_unref (addr); ++ return local; ++} ++ ++static void ++cancel_timer_cb (GCancellable *orig, GCancellable *to_cancel) ++{ ++ g_cancellable_cancel (to_cancel); ++} ++ ++static gboolean ++cancel_cancellable (gpointer cancellable) ++{ ++ g_cancellable_cancel (cancellable); ++ return FALSE; ++} ++ ++/** ++ * g_vfs_ftp_connection_accept_data_connection: ++ * @conn: a listening connection ++ * @cancellable: cancellable to interrupt wait ++ * @error: %NULL or location to take a potential error ++ * ++ * Opens a data connection for @conn by accepting an incoming connection on the ++ * address it is listening on via g_vfs_ftp_connection_listen_data_connection(), ++ * which must have been called prior to this function. ++ * If this function succeeds, a data connection will have been opened, and calls ++ * to g_vfs_ftp_connection_get_data_stream() will work. ++ * ++ * Returns: %TRUE if a connection was successfully acquired ++ **/ ++gboolean ++g_vfs_ftp_connection_accept_data_connection (GVfsFtpConnection *conn, ++ GCancellable * cancellable, ++ GError ** error) ++{ ++ GSocket *accepted; ++ GCancellable *timer; ++ gulong cancel_cb_id; ++ GIOCondition condition; ++ ++ g_return_val_if_fail (conn != NULL, FALSE); ++ g_return_val_if_fail (conn->data == NULL, FALSE); ++ g_return_val_if_fail (G_IS_SOCKET (conn->listen_socket), FALSE); ++ ++ timer = g_cancellable_new (); ++ cancel_cb_id = g_cancellable_connect (cancellable, ++ G_CALLBACK (cancel_timer_cb), ++ timer, ++ NULL); ++ g_object_ref (timer); ++ g_timeout_add_seconds_full (G_PRIORITY_DEFAULT, ++ G_VFS_FTP_TIMEOUT_IN_SECONDS, ++ cancel_cancellable, ++ timer, ++ g_object_unref); ++ ++ condition = g_socket_condition_wait (conn->listen_socket, G_IO_IN, timer, error); ++ ++ g_cancellable_disconnect (cancellable, cancel_cb_id); ++ g_object_unref (timer); ++ ++ if ((condition & G_IO_IN) == 0) ++ { ++ if (g_cancellable_is_cancelled (timer) && ++ !g_cancellable_is_cancelled (cancellable)) ++ { ++ g_clear_error (error); ++ g_set_error_literal (error, ++ G_IO_ERROR, G_IO_ERROR_HOST_NOT_FOUND, ++ _("Failed to create active FTP connection. " ++ "Maybe your router does not support this?")); ++ } ++ else if (error && *error == NULL) ++ { ++ g_set_error_literal (error, ++ G_IO_ERROR, G_IO_ERROR_HOST_NOT_FOUND, ++ _("Failed to create active FTP connection.")); ++ } ++ return FALSE; ++ } ++ ++ accepted = g_socket_accept (conn->listen_socket, error); ++ if (accepted == NULL) ++ return FALSE; ++ ++ conn->data = G_IO_STREAM (g_socket_connection_factory_create_connection (accepted)); ++ g_object_unref (accepted); ++ return TRUE; ++} ++ + void + g_vfs_ftp_connection_close_data_connection (GVfsFtpConnection *conn) + { +diff --git a/daemon/gvfsftpconnection.h b/daemon/gvfsftpconnection.h +index 3605f26..7d0c697 100644 +--- a/daemon/gvfsftpconnection.h ++++ b/daemon/gvfsftpconnection.h +@@ -55,6 +55,13 @@ gboolean g_vfs_ftp_connection_open_data_connection + GSocketAddress * addr, + GCancellable * cancellable, + GError ** error); ++GSocketAddress * g_vfs_ftp_connection_listen_data_connection ++ (GVfsFtpConnection * conn, ++ GError ** error); ++gboolean g_vfs_ftp_connection_accept_data_connection ++ (GVfsFtpConnection * conn, ++ GCancellable * cancellable, ++ GError ** error); + void g_vfs_ftp_connection_close_data_connection + (GVfsFtpConnection * conn); + GIOStream * g_vfs_ftp_connection_get_data_stream (GVfsFtpConnection * conn); +diff --git a/daemon/gvfsftptask.c b/daemon/gvfsftptask.c +index 37f2b59..879b912 100644 +--- a/daemon/gvfsftptask.c ++++ b/daemon/gvfsftptask.c +@@ -799,7 +799,6 @@ g_vfs_ftp_task_setup_data_connection_pasv (GVfsFtpTask *task, GVfsFtpMethod meth + guint status; + gboolean success; + +- /* only binary transfers please */ + status = g_vfs_ftp_task_send_and_check (task, 0, NULL, NULL, &reply, "PASV"); + if (status == 0) + return G_VFS_FTP_METHOD_ANY; +@@ -872,6 +871,45 @@ g_vfs_ftp_task_setup_data_connection_pasv (GVfsFtpTask *task, GVfsFtpMethod meth + return G_VFS_FTP_METHOD_ANY; + } + ++static GVfsFtpMethod ++g_vfs_ftp_task_open_data_connection_port (GVfsFtpTask *task, GVfsFtpMethod unused) ++{ ++ GSocketAddress *addr; ++ guint status, i, port; ++ char *ip_string; ++ ++ /* workaround for the task not having a connection yet */ ++ if (task->conn == NULL && ++ g_vfs_ftp_task_send (task, 0, "NOOP") == 0) ++ return G_VFS_FTP_METHOD_ANY; ++ ++ addr = g_vfs_ftp_connection_listen_data_connection (task->conn, &task->error); ++ if (addr == NULL) ++ return G_VFS_FTP_METHOD_ANY; ++ /* the PORT command only supports IPv4 */ ++ if (g_socket_address_get_family (addr) != G_SOCKET_FAMILY_IPV4) ++ { ++ g_object_unref (addr); ++ return G_VFS_FTP_METHOD_ANY; ++ } ++ ++ ip_string = g_inet_address_to_string (g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (addr))); ++ for (i = 0; ip_string[i]; i++) ++ { ++ if (ip_string[i] == '.') ++ ip_string[i] = ','; ++ } ++ port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr)); ++ ++ status = g_vfs_ftp_task_send (task, 0, "PORT %s,%u,%u", ip_string, port >> 8, port & 0xFF); ++ g_free (ip_string); ++ g_object_unref (addr); ++ if (status == 0) ++ return G_VFS_FTP_METHOD_ANY; ++ ++ return G_VFS_FTP_METHOD_PORT; ++} ++ + typedef GVfsFtpMethod (* GVfsFtpOpenDataConnectionFunc) (GVfsFtpTask *task, GVfsFtpMethod method); + + static GVfsFtpMethod +@@ -882,7 +920,8 @@ g_vfs_ftp_task_setup_data_connection_any (GVfsFtpTask *task, GVfsFtpMethod unuse + GVfsFtpOpenDataConnectionFunc func; + } funcs_ordered[] = { + { G_VFS_FTP_FEATURE_EPSV, g_vfs_ftp_task_setup_data_connection_epsv }, +- { 0, g_vfs_ftp_task_setup_data_connection_pasv } ++ { 0, g_vfs_ftp_task_setup_data_connection_pasv }, ++ { 0, g_vfs_ftp_task_open_data_connection_port } + }; + GVfsFtpMethod method; + guint i; +@@ -936,15 +975,15 @@ g_vfs_ftp_task_setup_data_connection (GVfsFtpTask *task) + [G_VFS_FTP_METHOD_PASV] = g_vfs_ftp_task_setup_data_connection_pasv, + [G_VFS_FTP_METHOD_PASV_ADDR] = g_vfs_ftp_task_setup_data_connection_pasv, + [G_VFS_FTP_METHOD_EPRT] = NULL, +- [G_VFS_FTP_METHOD_PORT] = NULL ++ [G_VFS_FTP_METHOD_PORT] = g_vfs_ftp_task_open_data_connection_port + }; + GVfsFtpMethod method, result; + + g_return_if_fail (task != NULL); + +- /* FIXME: get the method from elsewhere */ ++ task->method = G_VFS_FTP_METHOD_ANY; ++ + method = g_atomic_int_get (&task->backend->method); +- + g_assert (method < G_N_ELEMENTS (connect_funcs) && connect_funcs[method]); + + if (g_vfs_ftp_task_is_in_error (task)) +@@ -973,6 +1012,7 @@ g_vfs_ftp_task_setup_data_connection (GVfsFtpTask *task) + g_debug ("# set default data connection method from %s to %s\n", + methods[method], methods[result]); + } ++ task->method = result; + } + + /** +@@ -989,5 +1029,11 @@ g_vfs_ftp_task_open_data_connection (GVfsFtpTask *task) + + if (g_vfs_ftp_task_is_in_error (task)) + return; ++ ++ if (task->method == G_VFS_FTP_METHOD_EPRT || ++ task->method == G_VFS_FTP_METHOD_PORT) ++ g_vfs_ftp_connection_accept_data_connection (task->conn, ++ task->cancellable, ++ &task->error); + } + +diff --git a/daemon/gvfsftptask.h b/daemon/gvfsftptask.h +index 8345535..ac0bd74 100644 +--- a/daemon/gvfsftptask.h ++++ b/daemon/gvfsftptask.h +@@ -47,6 +47,7 @@ struct _GVfsFtpTask + + GError * error; /* NULL or current error - will be propagated to task */ + GVfsFtpConnection * conn; /* connection in use by this task or NULL if none */ ++ GVfsFtpMethod method; /* method currently in use (only valid after call to _setup_data_connection() */ + }; + + typedef void (* GVfsFtpErrorFunc) (GVfsFtpTask *task, gpointer data); +-- +1.6.3.2 + diff --git a/0004-FTP-add-the-error-code-for-EPRT-s-522-error.patch b/0004-FTP-add-the-error-code-for-EPRT-s-522-error.patch new file mode 100644 index 0000000..f36eae7 --- /dev/null +++ b/0004-FTP-add-the-error-code-for-EPRT-s-522-error.patch @@ -0,0 +1,27 @@ +From 81fb75b2dc11a969d890f58bc3255ceae3f7bfde Mon Sep 17 00:00:00 2001 +From: Benjamin Otte +Date: Tue, 16 Jun 2009 11:00:30 +0200 +Subject: [PATCH 04/13] [FTP] add the error code for EPRT's 522 error + +--- + daemon/gvfsftptask.c | 4 ++++ + 1 files changed, 4 insertions(+), 0 deletions(-) + +diff --git a/daemon/gvfsftptask.c b/daemon/gvfsftptask.c +index 879b912..318dde4 100644 +--- a/daemon/gvfsftptask.c ++++ b/daemon/gvfsftptask.c +@@ -382,6 +382,10 @@ g_vfs_ftp_task_set_error_from_response (GVfsFtpTask *task, guint response) + code = G_IO_ERROR_NOT_SUPPORTED; + msg = _("Operation unsupported"); + break; ++ case 522: /* EPRT: unsupported network protocol */ ++ code = G_IO_ERROR_NOT_SUPPORTED; ++ msg = _("Unsupported network protocol"); ++ break; + case 530: /* Not logged in. */ + code = G_IO_ERROR_PERMISSION_DENIED; + msg = _("Permission denied"); +-- +1.6.3.2 + diff --git a/0005-FTP-add-EPRT-support.patch b/0005-FTP-add-EPRT-support.patch new file mode 100644 index 0000000..df6d8bf --- /dev/null +++ b/0005-FTP-add-EPRT-support.patch @@ -0,0 +1,101 @@ +From 19a6bf345fdb8d445e4c3683e4ca0af0a0031f0b Mon Sep 17 00:00:00 2001 +From: Benjamin Otte +Date: Tue, 16 Jun 2009 11:16:27 +0200 +Subject: [PATCH 05/13] [FTP] add EPRT support + +The code does not support some corner cases that are listed in the RFC +(see inline comments), but I suspect those will never be hit. We can add +those when they are hit. +--- + daemon/gvfsftptask.c | 60 ++++++++++++++++++++++++++++++++++++++++++++----- + 1 files changed, 53 insertions(+), 7 deletions(-) + +diff --git a/daemon/gvfsftptask.c b/daemon/gvfsftptask.c +index 318dde4..9cab5a8 100644 +--- a/daemon/gvfsftptask.c ++++ b/daemon/gvfsftptask.c +@@ -876,7 +876,52 @@ g_vfs_ftp_task_setup_data_connection_pasv (GVfsFtpTask *task, GVfsFtpMethod meth + } + + static GVfsFtpMethod +-g_vfs_ftp_task_open_data_connection_port (GVfsFtpTask *task, GVfsFtpMethod unused) ++g_vfs_ftp_task_setup_data_connection_eprt (GVfsFtpTask *task, GVfsFtpMethod unused) ++{ ++ GSocketAddress *addr; ++ guint status, port, family; ++ char *ip_string; ++ ++ /* workaround for the task not having a connection yet */ ++ if (task->conn == NULL && ++ g_vfs_ftp_task_send (task, 0, "NOOP") == 0) ++ return G_VFS_FTP_METHOD_ANY; ++ ++ addr = g_vfs_ftp_connection_listen_data_connection (task->conn, &task->error); ++ if (addr == NULL) ++ return G_VFS_FTP_METHOD_ANY; ++ switch (g_socket_address_get_family (addr)) ++ { ++ case G_SOCKET_FAMILY_IPV4: ++ family = 1; ++ break; ++ case G_SOCKET_FAMILY_IPV6: ++ family = 2; ++ break; ++ default: ++ g_object_unref (addr); ++ return G_VFS_FTP_METHOD_ANY; ++ } ++ ++ ip_string = g_inet_address_to_string (g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (addr))); ++ /* if this ever happens (and it must not for IP4 and IP6 addresses), ++ * we need to add support for using a different separator */ ++ g_assert (strchr (ip_string, '|') == NULL); ++ port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr)); ++ ++ /* we could handle the 522 response here, (unsupported network family), ++ * but I don't think that will buy us anything */ ++ status = g_vfs_ftp_task_send (task, 0, "EPRT |%u|%s|%u|", family, ip_string, port); ++ g_free (ip_string); ++ g_object_unref (addr); ++ if (status == 0) ++ return G_VFS_FTP_METHOD_ANY; ++ ++ return G_VFS_FTP_METHOD_EPRT; ++} ++ ++static GVfsFtpMethod ++g_vfs_ftp_task_setup_data_connection_port (GVfsFtpTask *task, GVfsFtpMethod unused) + { + GSocketAddress *addr; + guint status, i, port; +@@ -925,7 +970,8 @@ g_vfs_ftp_task_setup_data_connection_any (GVfsFtpTask *task, GVfsFtpMethod unuse + } funcs_ordered[] = { + { G_VFS_FTP_FEATURE_EPSV, g_vfs_ftp_task_setup_data_connection_epsv }, + { 0, g_vfs_ftp_task_setup_data_connection_pasv }, +- { 0, g_vfs_ftp_task_open_data_connection_port } ++ { G_VFS_FTP_FEATURE_EPSV, g_vfs_ftp_task_setup_data_connection_eprt }, ++ { 0, g_vfs_ftp_task_setup_data_connection_port } + }; + GVfsFtpMethod method; + guint i; +@@ -974,12 +1020,12 @@ void + g_vfs_ftp_task_setup_data_connection (GVfsFtpTask *task) + { + static const GVfsFtpOpenDataConnectionFunc connect_funcs[] = { +- [G_VFS_FTP_METHOD_ANY] = g_vfs_ftp_task_setup_data_connection_any, +- [G_VFS_FTP_METHOD_EPSV] = g_vfs_ftp_task_setup_data_connection_epsv, +- [G_VFS_FTP_METHOD_PASV] = g_vfs_ftp_task_setup_data_connection_pasv, ++ [G_VFS_FTP_METHOD_ANY] = g_vfs_ftp_task_setup_data_connection_any, ++ [G_VFS_FTP_METHOD_EPSV] = g_vfs_ftp_task_setup_data_connection_epsv, ++ [G_VFS_FTP_METHOD_PASV] = g_vfs_ftp_task_setup_data_connection_pasv, + [G_VFS_FTP_METHOD_PASV_ADDR] = g_vfs_ftp_task_setup_data_connection_pasv, +- [G_VFS_FTP_METHOD_EPRT] = NULL, +- [G_VFS_FTP_METHOD_PORT] = g_vfs_ftp_task_open_data_connection_port ++ [G_VFS_FTP_METHOD_EPRT] = g_vfs_ftp_task_setup_data_connection_eprt, ++ [G_VFS_FTP_METHOD_PORT] = g_vfs_ftp_task_setup_data_connection_port + }; + GVfsFtpMethod method, result; + +-- +1.6.3.2 + diff --git a/0006-Bug-582772-gvfsd-computer-crashes-with-SEGSEV-in-rec.patch b/0006-Bug-582772-gvfsd-computer-crashes-with-SEGSEV-in-rec.patch new file mode 100644 index 0000000..206871b --- /dev/null +++ b/0006-Bug-582772-gvfsd-computer-crashes-with-SEGSEV-in-rec.patch @@ -0,0 +1,36 @@ +From 5d3ab40b5b0a574f207e7177d2f4c3bd329458a4 Mon Sep 17 00:00:00 2001 +From: David Zeuthen +Date: Tue, 16 Jun 2009 17:41:45 -0400 +Subject: [PATCH 06/13] =?utf-8?q?Bug=20582772=20=E2=80=93=20gvfsd-computer=20crashes=20with=20SEGSEV=20in=20recompute=5Ffiles?= +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: 8bit + +Never use blank/empty drive names. +--- + monitor/gdu/ggdudrive.c | 9 +++++++++ + 1 files changed, 9 insertions(+), 0 deletions(-) + +diff --git a/monitor/gdu/ggdudrive.c b/monitor/gdu/ggdudrive.c +index 8e04104..6195f97 100644 +--- a/monitor/gdu/ggdudrive.c ++++ b/monitor/gdu/ggdudrive.c +@@ -177,6 +177,15 @@ update_drive (GGduDrive *drive) + if (device != NULL) + g_object_unref (device); + ++ /* Never use empty/blank names (#582772) */ ++ if (drive->name == NULL || strlen (drive->name) == 0) ++ { ++ if (drive->device_file != NULL) ++ drive->name = g_strdup_printf (_("Unnamed Drive (%s)"), drive->device_file); ++ else ++ drive->name = g_strdup (_("Unnamed Drive")); ++ } ++ + /* compute whether something changed */ + changed = !((old_is_media_removable == drive->is_media_removable) && + (old_has_media == drive->has_media) && +-- +1.6.3.2 + diff --git a/0007-Better-handling-of-PC-floppy-drives.patch b/0007-Better-handling-of-PC-floppy-drives.patch new file mode 100644 index 0000000..a365b79 --- /dev/null +++ b/0007-Better-handling-of-PC-floppy-drives.patch @@ -0,0 +1,117 @@ +From c6405c6653c27b247f1fbb59c01b95938fb6b2d8 Mon Sep 17 00:00:00 2001 +From: David Zeuthen +Date: Tue, 16 Jun 2009 19:49:38 -0400 +Subject: [PATCH 07/13] Better handling of PC floppy drives + +PC Floppy Drives are handled in a special way since we don't poll for +media (it would make a lot of noise). Specifically we never probe for +the filesystem type. So if encountering a PC Floppy Drive, just always +show all volumes from it. Since we already have working support for +g_drive_poll_for_media() in Nautilus, things Just Work(tm) + +http://people.freedesktop.org/~david/dkd-gnome-floppy-welcome-to-the-1980s.png + +E.g. you can use the "Rescan" menu option to force media detection. + +Welcome to the 1980s. +--- + monitor/gdu/ggdudrive.c | 5 ++++- + monitor/gdu/ggduvolume.c | 5 ++++- + monitor/gdu/ggduvolumemonitor.c | 28 +++++++++++++++++++++++++++- + monitor/gdu/ggduvolumemonitor.h | 2 ++ + 4 files changed, 37 insertions(+), 3 deletions(-) + +diff --git a/monitor/gdu/ggdudrive.c b/monitor/gdu/ggdudrive.c +index 6195f97..d332e14 100644 +--- a/monitor/gdu/ggdudrive.c ++++ b/monitor/gdu/ggdudrive.c +@@ -148,7 +148,10 @@ update_drive (GGduDrive *drive) + drive->icon = gdu_presentable_get_icon (drive->presentable); + + g_free (drive->name); +- drive->name = gdu_presentable_get_name (drive->presentable); ++ if (_is_pc_floppy_drive (device)) ++ drive->name = g_strdup (_("Floppy Drive")); ++ else ++ drive->name = gdu_presentable_get_name (drive->presentable); + + /* the GduDevice for an activatable drive (such as RAID) is NULL if the drive is not activated */ + if (device == NULL) +diff --git a/monitor/gdu/ggduvolume.c b/monitor/gdu/ggduvolume.c +index 8f75247..73ad0fc 100644 +--- a/monitor/gdu/ggduvolume.c ++++ b/monitor/gdu/ggduvolume.c +@@ -304,7 +304,10 @@ update_volume (GGduVolume *volume) + volume->icon = gdu_presentable_get_icon (GDU_PRESENTABLE (volume->gdu_volume)); + + g_free (volume->name); +- volume->name = gdu_presentable_get_name (GDU_PRESENTABLE (volume->gdu_volume)); ++ if (_is_pc_floppy_drive (device)) ++ volume->name = g_strdup (_("Floppy Disk")); ++ else ++ volume->name = gdu_presentable_get_name (GDU_PRESENTABLE (volume->gdu_volume)); + + /* special case the name and icon for audio discs */ + activation_uri = volume->activation_root != NULL ? g_file_get_uri (volume->activation_root) : NULL; +diff --git a/monitor/gdu/ggduvolumemonitor.c b/monitor/gdu/ggduvolumemonitor.c +index 5c80f64..6da7393 100644 +--- a/monitor/gdu/ggduvolumemonitor.c ++++ b/monitor/gdu/ggduvolumemonitor.c +@@ -744,6 +744,32 @@ should_mount_be_ignored (GduPool *pool, GduDevice *d) + return ret; + } + ++gboolean ++_is_pc_floppy_drive (GduDevice *device) ++{ ++ gboolean ret; ++ gchar **drive_media_compat; ++ const gchar *drive_connection_interface; ++ ++ ret = FALSE; ++ ++ if (device != NULL) ++ { ++ drive_media_compat = gdu_device_drive_get_media_compatibility (device); ++ drive_connection_interface = gdu_device_drive_get_connection_interface (device); ++ ++ if (g_strcmp0 (drive_connection_interface, "platform") == 0 && ++ (drive_media_compat != NULL && ++ g_strv_length (drive_media_compat) > 0 && ++ g_strcmp0 (drive_media_compat[0], "floppy") == 0)) ++ { ++ ret = TRUE; ++ } ++ } ++ ++ return ret; ++} ++ + static gboolean + should_volume_be_ignored (GduPool *pool, GduVolume *volume, GList *fstab_mount_points) + { +@@ -763,7 +789,7 @@ should_volume_be_ignored (GduPool *pool, GduVolume *volume, GList *fstab_mount_p + usage = gdu_device_id_get_usage (device); + type = gdu_device_id_get_type (device); + +- if (g_strcmp0 (usage, "filesystem") == 0) ++ if (_is_pc_floppy_drive (device) || g_strcmp0 (usage, "filesystem") == 0) + { + GUnixMountPoint *mount_point; + +diff --git a/monitor/gdu/ggduvolumemonitor.h b/monitor/gdu/ggduvolumemonitor.h +index ec559c4..b91ceb9 100644 +--- a/monitor/gdu/ggduvolumemonitor.h ++++ b/monitor/gdu/ggduvolumemonitor.h +@@ -55,6 +55,8 @@ GType g_gdu_volume_monitor_get_type (void) G_GNUC_CONST; + + GVolumeMonitor *g_gdu_volume_monitor_new (void); + ++gboolean _is_pc_floppy_drive (GduDevice *device); ++ + G_END_DECLS + + #endif /* __G_GDU_VOLUME_MONITOR_H__ */ +-- +1.6.3.2 + diff --git a/0008-FTP-use-the-EPRT-feature-response-for-EPRT-support-n.patch b/0008-FTP-use-the-EPRT-feature-response-for-EPRT-support-n.patch new file mode 100644 index 0000000..62a1009 --- /dev/null +++ b/0008-FTP-use-the-EPRT-feature-response-for-EPRT-support-n.patch @@ -0,0 +1,51 @@ +From acb3f8029d9f9a7054e3f138fd978e24233573a3 Mon Sep 17 00:00:00 2001 +From: Benjamin Otte +Date: Wed, 17 Jun 2009 10:04:42 +0200 +Subject: [PATCH 08/13] [FTP] use the EPRT feature response for EPRT support, not EPSV + +--- + daemon/gvfsbackendftp.c | 1 + + daemon/gvfsbackendftp.h | 1 + + daemon/gvfsftptask.c | 2 +- + 3 files changed, 3 insertions(+), 1 deletions(-) + +diff --git a/daemon/gvfsbackendftp.c b/daemon/gvfsbackendftp.c +index 913eb1c..aef5687 100644 +--- a/daemon/gvfsbackendftp.c ++++ b/daemon/gvfsbackendftp.c +@@ -99,6 +99,7 @@ gvfs_backend_ftp_determine_features (GVfsFtpTask *task) + { "MDTM", G_VFS_FTP_FEATURE_MDTM }, + { "SIZE", G_VFS_FTP_FEATURE_SIZE }, + { "TVFS", G_VFS_FTP_FEATURE_TVFS }, ++ { "EPRT", G_VFS_FTP_FEATURE_EPRT }, + { "EPSV", G_VFS_FTP_FEATURE_EPSV }, + { "UTF8", G_VFS_FTP_FEATURE_UTF8 }, + }; +diff --git a/daemon/gvfsbackendftp.h b/daemon/gvfsbackendftp.h +index 89b2769..0a7bcf5 100644 +--- a/daemon/gvfsbackendftp.h ++++ b/daemon/gvfsbackendftp.h +@@ -34,6 +34,7 @@ typedef enum { + G_VFS_FTP_FEATURE_MDTM, + G_VFS_FTP_FEATURE_SIZE, + G_VFS_FTP_FEATURE_TVFS, ++ G_VFS_FTP_FEATURE_EPRT, + G_VFS_FTP_FEATURE_EPSV, + G_VFS_FTP_FEATURE_UTF8 + } GVfsFtpFeature; +diff --git a/daemon/gvfsftptask.c b/daemon/gvfsftptask.c +index 9cab5a8..4c46c0c 100644 +--- a/daemon/gvfsftptask.c ++++ b/daemon/gvfsftptask.c +@@ -970,7 +970,7 @@ g_vfs_ftp_task_setup_data_connection_any (GVfsFtpTask *task, GVfsFtpMethod unuse + } funcs_ordered[] = { + { G_VFS_FTP_FEATURE_EPSV, g_vfs_ftp_task_setup_data_connection_epsv }, + { 0, g_vfs_ftp_task_setup_data_connection_pasv }, +- { G_VFS_FTP_FEATURE_EPSV, g_vfs_ftp_task_setup_data_connection_eprt }, ++ { G_VFS_FTP_FEATURE_EPRT, g_vfs_ftp_task_setup_data_connection_eprt }, + { 0, g_vfs_ftp_task_setup_data_connection_port } + }; + GVfsFtpMethod method; +-- +1.6.3.2 + diff --git a/0009-FTP-remove-EPSV-as-default-feature.patch b/0009-FTP-remove-EPSV-as-default-feature.patch new file mode 100644 index 0000000..fe2f44b --- /dev/null +++ b/0009-FTP-remove-EPSV-as-default-feature.patch @@ -0,0 +1,27 @@ +From 056cfe684e3db4f83c176bb723c264ecfe60837f Mon Sep 17 00:00:00 2001 +From: Benjamin Otte +Date: Wed, 17 Jun 2009 10:05:29 +0200 +Subject: [PATCH 09/13] [FTP] remove EPSV as default feature + +now that we try EPSV anyway, we can omit assuming it exists and try PASV +first. +--- + daemon/gvfsbackendftp.h | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/daemon/gvfsbackendftp.h b/daemon/gvfsbackendftp.h +index 0a7bcf5..5923d17 100644 +--- a/daemon/gvfsbackendftp.h ++++ b/daemon/gvfsbackendftp.h +@@ -38,7 +38,7 @@ typedef enum { + G_VFS_FTP_FEATURE_EPSV, + G_VFS_FTP_FEATURE_UTF8 + } GVfsFtpFeature; +-#define G_VFS_FTP_FEATURES_DEFAULT (1 << G_VFS_FTP_FEATURE_EPSV) ++#define G_VFS_FTP_FEATURES_DEFAULT (0) + + typedef enum { + G_VFS_FTP_SYSTEM_UNKNOWN = 0, +-- +1.6.3.2 + diff --git a/0014-gvfs-use-device-media-detected.patch b/0014-gvfs-use-device-media-detected.patch deleted file mode 100644 index 15df34e..0000000 --- a/0014-gvfs-use-device-media-detected.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 3f3f21fe6e2bdac8fd6acf048da6fb228adde092 Mon Sep 17 00:00:00 2001 -From: David Zeuthen -Date: Fri, 01 May 2009 19:59:54 +0000 -Subject: Use new gnome-disk-utility API to figure out when media was inserted - -This fixes a problem with Nautilus automounting newly created volumes -appearing as a result of formatting/partitioning. ---- -diff --git a/monitor/gdu/ggdudrive.c b/monitor/gdu/ggdudrive.c -index 29e108d..c2c8b76 100644 ---- a/monitor/gdu/ggdudrive.c -+++ b/monitor/gdu/ggdudrive.c -@@ -51,7 +51,6 @@ struct _GGduDrive { - gboolean can_eject; - gboolean can_poll_for_media; - gboolean is_media_check_automatic; -- time_t time_of_last_media_insertion; - }; - - static void g_gdu_drive_drive_iface_init (GDriveIface *iface); -@@ -178,9 +177,6 @@ update_drive (GGduDrive *drive) - if (device != NULL) - g_object_unref (device); - -- if (drive->has_media != old_has_media) -- drive->time_of_last_media_insertion = time (NULL); -- - /* compute whether something changed */ - changed = !((old_is_media_removable == drive->is_media_removable) && - (old_has_media == drive->has_media) && -@@ -233,8 +229,6 @@ g_gdu_drive_new (GVolumeMonitor *volume_monitor, - - drive->presentable = g_object_ref (presentable); - -- drive->time_of_last_media_insertion = time (NULL); -- - g_signal_connect (drive->presentable, "changed", G_CALLBACK (presentable_changed), drive); - g_signal_connect (drive->presentable, "job-changed", G_CALLBACK (presentable_job_changed), drive); - -@@ -685,7 +679,16 @@ g_gdu_drive_has_presentable (GGduDrive *drive, - time_t - g_gdu_drive_get_time_of_last_media_insertion (GGduDrive *drive) - { -- return drive->time_of_last_media_insertion; -+ GduDevice *device; -+ time_t ret; -+ -+ ret = 0; -+ device = gdu_presentable_get_device (drive->presentable); -+ if (device != NULL) { -+ ret = gdu_device_get_media_detection_time (device); -+ g_object_unref (device); -+ } -+ return ret; - } - - GduPresentable * --- -cgit v0.8.2 diff --git a/0015-gvfs-respect-presentation-hide-for-drives.patch b/0015-gvfs-respect-presentation-hide-for-drives.patch deleted file mode 100644 index 17a2ea4..0000000 --- a/0015-gvfs-respect-presentation-hide-for-drives.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 59dd3b33a71a930651f23142e2a7d7e57727144f Mon Sep 17 00:00:00 2001 -From: David Zeuthen -Date: Fri, 01 May 2009 21:23:01 +0000 -Subject: Fix bug where drives are not ignored as they ought to be - -This should fix part of - - https://bugzilla.redhat.com/show_bug.cgi?id=498649#c14 - -(the other part is fixed in the Fedora livecd scripts) ---- -diff --git a/monitor/gdu/ggduvolumemonitor.c b/monitor/gdu/ggduvolumemonitor.c -index 2c1f727..df42249 100644 ---- a/monitor/gdu/ggduvolumemonitor.c -+++ b/monitor/gdu/ggduvolumemonitor.c -@@ -833,8 +833,10 @@ should_drive_be_ignored (GduPool *pool, GduDrive *d, GList *fstab_mount_points) - goto out; - } - -- if (gdu_device_get_presentation_hide (device)) -+ if (gdu_device_get_presentation_hide (device)) { -+ ignored = TRUE; - goto out; -+ } - - has_volumes = FALSE; - all_volumes_are_ignored = TRUE; --- -cgit v0.8.2 diff --git a/gdu-0001-Bug-573826-gdu-volume-monitor.patch b/gdu-0001-Bug-573826-gdu-volume-monitor.patch deleted file mode 100644 index 6731f35..0000000 --- a/gdu-0001-Bug-573826-gdu-volume-monitor.patch +++ /dev/null @@ -1,5250 +0,0 @@ -From 9d51c0de20170731db25422e858fee0e44b1dbd1 Mon Sep 17 00:00:00 2001 -From: David Zeuthen -Date: Thu, 9 Apr 2009 19:01:18 -0400 -Subject: [PATCH 1/7] =?utf-8?q?Bug=20573826=20=E2=80=93=20gdu=20volume=20monitor?= -MIME-Version: 1.0 -Content-Type: text/plain; charset=utf-8 -Content-Transfer-Encoding: 8bit - -Add the GNOME Disk Utility based volume monitor, see - - http://bugzilla.gnome.org/show_bug.cgi?id=573826 - http://mail.gnome.org/archives/gvfs-list/2009-March/msg00002.html - -for details. ---- - configure.ac | 28 +- - monitor/Makefile.am | 4 + - monitor/gdu/Makefile.am | 53 + - monitor/gdu/gdu-volume-monitor-daemon.c | 46 + - monitor/gdu/gdu.monitor | 5 + - monitor/gdu/ggdudrive.c | 691 ++++++++++ - monitor/gdu/ggdudrive.h | 69 + - monitor/gdu/ggdumount.c | 958 +++++++++++++ - monitor/gdu/ggdumount.h | 64 + - monitor/gdu/ggduvolume.c | 1408 +++++++++++++++++++ - monitor/gdu/ggduvolume.h | 78 ++ - monitor/gdu/ggduvolumemonitor.c | 1432 ++++++++++++++++++++ - monitor/gdu/ggduvolumemonitor.h | 60 + - .../org.gtk.Private.GduVolumeMonitor.service.in | 3 + - monitor/gdu/polkit.c | 137 ++ - monitor/gdu/polkit.h | 44 + - 16 files changed, 5079 insertions(+), 1 deletions(-) - create mode 100644 monitor/gdu/Makefile.am - create mode 100644 monitor/gdu/gdu-volume-monitor-daemon.c - create mode 100644 monitor/gdu/gdu.monitor - create mode 100644 monitor/gdu/ggdudrive.c - create mode 100644 monitor/gdu/ggdudrive.h - create mode 100644 monitor/gdu/ggdumount.c - create mode 100644 monitor/gdu/ggdumount.h - create mode 100644 monitor/gdu/ggduvolume.c - create mode 100644 monitor/gdu/ggduvolume.h - create mode 100644 monitor/gdu/ggduvolumemonitor.c - create mode 100644 monitor/gdu/ggduvolumemonitor.h - create mode 100644 monitor/gdu/org.gtk.Private.GduVolumeMonitor.service.in - create mode 100644 monitor/gdu/polkit.c - create mode 100644 monitor/gdu/polkit.h - -diff --git a/configure.ac b/configure.ac -index 311127e..895309b 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -198,6 +198,30 @@ AC_SUBST(GCONF_CFLAGS) - - AM_CONDITIONAL(USE_GCONF, [test "$msg_gconf" = "yes"]) - -+dnl ************************************ -+dnl *** Check for gnome-disk-utility *** -+dnl ************************************ -+ -+AC_ARG_ENABLE(gdu, [ --disable-gdu build without GDU volume monitor]) -+msg_gdu=no -+GDU_LIBS= -+GDU_CFLAGS= -+GDU_REQUIRED=0.3 -+ -+if test "x$enable_gdu" != "xno"; then -+ PKG_CHECK_EXISTS([gdu >= $GDU_REQUIRED], msg_gdu=yes) -+ -+ if test "x$msg_gdu" == "xyes"; then -+ PKG_CHECK_MODULES([GDU],[gdu >= $GDU_REQUIRED]) -+ AC_DEFINE(HAVE_GDU, 1, [Define to 1 if gnome-disk-utility is available]) -+ fi -+fi -+ -+AC_SUBST(GDU_LIBS) -+AC_SUBST(GDU_CFLAGS) -+ -+AM_CONDITIONAL(USE_GDU, [test "$msg_gdu" = "yes"]) -+ - dnl ********************** - dnl *** Check for HAL *** - dnl ********************** -@@ -558,6 +582,7 @@ daemon/Makefile - monitor/Makefile - monitor/proxy/Makefile - monitor/hal/Makefile -+monitor/gdu/Makefile - monitor/gphoto2/Makefile - gconf/Makefile - programs/Makefile -@@ -579,7 +604,8 @@ echo " - archive support: $msg_archive - GConf support: $msg_gconf - DNS-SD support: $msg_avahi -- Use HAL for volume monitor: $msg_hal (with fast init path: $have_hal_fast_init) -+ Build HAL volume monitor: $msg_hal (with fast init path: $have_hal_fast_init) -+ Build GDU volume monitor: $msg_gdu - GNOME Keyring support: $msg_keyring - Bash-completion support: $msg_bash_completion - " -diff --git a/monitor/Makefile.am b/monitor/Makefile.am -index d4197d5..f68423e 100644 ---- a/monitor/Makefile.am -+++ b/monitor/Makefile.am -@@ -5,6 +5,10 @@ if USE_HAL - SUBDIRS += hal - endif - -+if USE_GDU -+SUBDIRS += gdu -+endif -+ - if USE_GPHOTO2 - SUBDIRS += gphoto2 - endif -diff --git a/monitor/gdu/Makefile.am b/monitor/gdu/Makefile.am -new file mode 100644 -index 0000000..10b80f3 ---- /dev/null -+++ b/monitor/gdu/Makefile.am -@@ -0,0 +1,53 @@ -+ -+NULL = -+ -+libexec_PROGRAMS = gvfs-gdu-volume-monitor -+ -+ -+gvfs_gdu_volume_monitor_SOURCES = \ -+ gdu-volume-monitor-daemon.c \ -+ ggdudrive.c ggdudrive.h \ -+ ggduvolume.c ggduvolume.h \ -+ ggdumount.c ggdumount.h \ -+ ggduvolumemonitor.c ggduvolumemonitor.h \ -+ polkit.c polkit.h \ -+ $(NULL) -+ -+gvfs_gdu_volume_monitor_CFLAGS = \ -+ -DG_LOG_DOMAIN=\"GVFS-Gdu\" \ -+ -I$(top_srcdir)/common \ -+ -I$(top_srcdir)/monitor/proxy \ -+ $(GLIB_CFLAGS) \ -+ $(GDU_CFLAGS) \ -+ $(DBUS_CFLAGS) \ -+ -DGIO_MODULE_DIR=\"$(GIO_MODULE_DIR)\" \ -+ -DGVFS_LOCALEDIR=\""$(localedir)"\" \ -+ -DG_DISABLE_DEPRECATED \ -+ -DGDU_API_IS_SUBJECT_TO_CHANGE \ -+ $(NULL) -+ -+gvfs_gdu_volume_monitor_LDFLAGS = \ -+ $(NULL) -+ -+gvfs_gdu_volume_monitor_LDADD = \ -+ $(GLIB_LIBS) \ -+ $(GDU_LIBS) \ -+ $(DBUS_LIBS) \ -+ $(top_builddir)/common/libgvfscommon.la \ -+ $(top_builddir)/monitor/proxy/libgvfsproxyvolumemonitordaemon-noin.la \ -+ $(NULL) -+ -+remote_volume_monitorsdir = $(datadir)/gvfs/remote-volume-monitors -+remote_volume_monitors_DATA = gdu.monitor -+ -+servicedir = $(datadir)/dbus-1/services -+service_in_files = org.gtk.Private.GduVolumeMonitor.service.in -+service_DATA = $(service_in_files:.service.in=.service) -+ -+$(service_DATA): $(service_in_files) Makefile -+ @sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@ -+ -+clean-local: -+ rm -f *~ *.loT $(BUILT_SOURCES) $(service_DATA) -+ -+EXTRA_DIST = $(service_in_files) gdu.monitor -diff --git a/monitor/gdu/gdu-volume-monitor-daemon.c b/monitor/gdu/gdu-volume-monitor-daemon.c -new file mode 100644 -index 0000000..cdb4f84 ---- /dev/null -+++ b/monitor/gdu/gdu-volume-monitor-daemon.c -@@ -0,0 +1,46 @@ -+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -+/* gvfs - extensions for gio -+ * -+ * Copyright (C) 2006-2009 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., 59 Temple Place, Suite 330, -+ * Boston, MA 02111-1307, USA. -+ * -+ * Author: David Zeuthen -+ */ -+ -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+ -+#include "ggduvolumemonitor.h" -+ -+int -+main (int argc, char *argv[]) -+{ -+ g_vfs_proxy_volume_monitor_daemon_init (); -+ -+ g_set_application_name (_("GVfs GDU Volume Monitor")); -+ -+ return g_vfs_proxy_volume_monitor_daemon_main (argc, -+ argv, -+ "org.gtk.Private.GduVolumeMonitor", -+ G_TYPE_GDU_VOLUME_MONITOR); -+} -diff --git a/monitor/gdu/gdu.monitor b/monitor/gdu/gdu.monitor -new file mode 100644 -index 0000000..9a97695 ---- /dev/null -+++ b/monitor/gdu/gdu.monitor -@@ -0,0 +1,5 @@ -+[RemoteVolumeMonitor] -+Name=GProxyVolumeMonitorGdu -+DBusName=org.gtk.Private.GduVolumeMonitor -+IsNative=true -+NativePriority=3 -diff --git a/monitor/gdu/ggdudrive.c b/monitor/gdu/ggdudrive.c -new file mode 100644 -index 0000000..257a113 ---- /dev/null -+++ b/monitor/gdu/ggdudrive.c -@@ -0,0 +1,691 @@ -+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -+/* gvfs - extensions for gio -+ * -+ * Copyright (C) 2006-2009 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., 59 Temple Place, Suite 330, -+ * Boston, MA 02111-1307, USA. -+ * -+ * Author: David Zeuthen -+ */ -+ -+#include -+ -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "ggduvolumemonitor.h" -+#include "ggdudrive.h" -+#include "ggduvolume.h" -+ -+struct _GGduDrive { -+ GObject parent; -+ -+ GVolumeMonitor *volume_monitor; /* owned by volume monitor */ -+ GList *volumes; /* entries in list are owned by volume_monitor */ -+ -+ GduPresentable *presentable; -+ -+ /* the following members need to be set upon construction */ -+ GIcon *icon; -+ gchar *name; -+ gchar *device_file; -+ gboolean is_media_removable; -+ gboolean has_media; -+ gboolean can_eject; -+ gboolean can_poll_for_media; -+ gboolean is_media_check_automatic; -+ time_t time_of_last_media_insertion; -+}; -+ -+static void g_gdu_drive_drive_iface_init (GDriveIface *iface); -+ -+G_DEFINE_TYPE_EXTENDED (GGduDrive, g_gdu_drive, G_TYPE_OBJECT, 0, -+ G_IMPLEMENT_INTERFACE (G_TYPE_DRIVE, -+ g_gdu_drive_drive_iface_init)) -+ -+static void presentable_changed (GduPresentable *presentable, -+ GGduDrive *drive); -+ -+static void presentable_job_changed (GduPresentable *presentable, -+ GGduDrive *drive); -+ -+static void -+g_gdu_drive_finalize (GObject *object) -+{ -+ GList *l; -+ GGduDrive *drive; -+ -+ drive = G_GDU_DRIVE (object); -+ -+ for (l = drive->volumes; l != NULL; l = l->next) -+ { -+ GGduVolume *volume = l->data; -+ g_gdu_volume_unset_drive (volume, drive); -+ } -+ -+ if (drive->presentable != NULL) -+ { -+ g_signal_handlers_disconnect_by_func (drive->presentable, presentable_changed, drive); -+ g_signal_handlers_disconnect_by_func (drive->presentable, presentable_job_changed, drive); -+ g_object_unref (drive->presentable); -+ } -+ -+ if (drive->icon != NULL) -+ g_object_unref (drive->icon); -+ g_free (drive->name); -+ g_free (drive->device_file); -+ -+ if (G_OBJECT_CLASS (g_gdu_drive_parent_class)->finalize) -+ (*G_OBJECT_CLASS (g_gdu_drive_parent_class)->finalize) (object); -+} -+ -+static void -+g_gdu_drive_class_init (GGduDriveClass *klass) -+{ -+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass); -+ -+ gobject_class->finalize = g_gdu_drive_finalize; -+} -+ -+static void -+g_gdu_drive_init (GGduDrive *gdu_drive) -+{ -+} -+ -+static void -+emit_changed (GGduDrive *drive) -+{ -+ g_signal_emit_by_name (drive, "changed"); -+ g_signal_emit_by_name (drive->volume_monitor, "drive_changed", drive); -+} -+ -+static gboolean -+update_drive (GGduDrive *drive) -+{ -+ GduDevice *device; -+ gboolean changed; -+ GIcon *old_icon; -+ gchar *old_name; -+ gchar *old_device_file; -+ gboolean old_is_media_removable; -+ gboolean old_has_media; -+ gboolean old_can_eject; -+ gboolean old_is_media_check_automatic; -+ gboolean old_can_poll_for_media; -+ -+ /* save old values */ -+ old_is_media_removable = drive->is_media_removable; -+ old_has_media = drive->has_media; -+ old_can_eject = drive->can_eject; -+ old_can_poll_for_media = drive->can_poll_for_media; -+ old_is_media_check_automatic = drive->is_media_check_automatic; -+ -+ old_name = g_strdup (drive->name); -+ old_device_file = g_strdup (drive->device_file); -+ old_icon = drive->icon != NULL ? g_object_ref (drive->icon) : NULL; -+ -+ /* in with the new */ -+ device = gdu_presentable_get_device (drive->presentable); -+ -+ if (drive->icon != NULL) -+ g_object_unref (drive->icon); -+ drive->icon = gdu_presentable_get_icon (drive->presentable); -+ -+ g_free (drive->name); -+ drive->name = gdu_presentable_get_name (drive->presentable); -+ -+ /* the GduDevice for an activatable drive (such as RAID) is NULL if the drive is not activated */ -+ if (device == NULL) -+ { -+ g_free (drive->device_file); -+ drive->device_file = NULL; -+ drive->is_media_removable = TRUE; -+ drive->has_media = TRUE; -+ drive->can_eject = FALSE; -+ } -+ else -+ { -+ g_free (drive->device_file); -+ drive->device_file = g_strdup (gdu_device_get_device_file (device)); -+ drive->is_media_removable = gdu_device_is_removable (device); -+ drive->has_media = gdu_device_is_media_available (device); -+ drive->can_eject = gdu_device_drive_get_is_media_ejectable (device) || gdu_device_drive_get_requires_eject (device); -+ drive->is_media_check_automatic = gdu_device_is_media_change_detected (device); -+ drive->can_poll_for_media = TRUE; -+ } -+ -+ if (device != NULL) -+ g_object_unref (device); -+ -+ if (drive->has_media != old_has_media) -+ drive->time_of_last_media_insertion = time (NULL); -+ -+ /* compute whether something changed */ -+ changed = !((old_is_media_removable == drive->is_media_removable) && -+ (old_has_media == drive->has_media) && -+ (old_can_eject == drive->can_eject) && -+ (old_is_media_check_automatic == drive->is_media_check_automatic) && -+ (old_can_poll_for_media == drive->can_poll_for_media) && -+ (g_strcmp0 (old_name, drive->name) == 0) && -+ (g_strcmp0 (old_device_file, drive->device_file) == 0) && -+ g_icon_equal (old_icon, drive->icon) -+ ); -+ -+ /* free old values */ -+ g_free (old_name); -+ g_free (old_device_file); -+ if (old_icon != NULL) -+ g_object_unref (old_icon); -+ -+ /*g_debug ("in update_drive(); has_media=%d changed=%d", drive->has_media, changed);*/ -+ -+ return changed; -+} -+ -+static void -+presentable_changed (GduPresentable *presentable, -+ GGduDrive *drive) -+{ -+ /*g_debug ("drive: presentable_changed: %p: %s", drive, gdu_presentable_get_id (GDU_PRESENTABLE (presentable)));*/ -+ if (update_drive (drive)) -+ emit_changed (drive); -+} -+ -+static void -+presentable_job_changed (GduPresentable *presentable, -+ GGduDrive *drive) -+{ -+ /*g_debug ("drive: presentable_job_changed: %p: %s", drive, gdu_presentable_get_id (GDU_PRESENTABLE (presentable)));*/ -+ if (update_drive (drive)) -+ emit_changed (drive); -+} -+ -+GGduDrive * -+g_gdu_drive_new (GVolumeMonitor *volume_monitor, -+ GduPresentable *presentable) -+{ -+ GGduDrive *drive; -+ -+ drive = g_object_new (G_TYPE_GDU_DRIVE, NULL); -+ drive->volume_monitor = volume_monitor; -+ g_object_add_weak_pointer (G_OBJECT (volume_monitor), (gpointer) &(drive->volume_monitor)); -+ -+ drive->presentable = g_object_ref (presentable); -+ -+ drive->time_of_last_media_insertion = time (NULL); -+ -+ g_signal_connect (drive->presentable, "changed", G_CALLBACK (presentable_changed), drive); -+ g_signal_connect (drive->presentable, "job-changed", G_CALLBACK (presentable_job_changed), drive); -+ -+ update_drive (drive); -+ -+ return drive; -+} -+ -+void -+g_gdu_drive_disconnected (GGduDrive *drive) -+{ -+ GList *l, *volumes; -+ -+ volumes = drive->volumes; -+ drive->volumes = NULL; -+ -+ for (l = volumes; l != NULL; l = l->next) -+ { -+ GGduVolume *volume = l->data; -+ g_gdu_volume_unset_drive (volume, drive); -+ } -+ -+ g_list_free (volumes); -+} -+ -+void -+g_gdu_drive_set_volume (GGduDrive *drive, -+ GGduVolume *volume) -+{ -+ if (g_list_find (drive->volumes, volume) == NULL) -+ { -+ drive->volumes = g_list_prepend (drive->volumes, volume); -+ emit_changed (drive); -+ } -+} -+ -+void -+g_gdu_drive_unset_volume (GGduDrive *drive, -+ GGduVolume *volume) -+{ -+ GList *l; -+ -+ l = g_list_find (drive->volumes, volume); -+ if (l != NULL) -+ { -+ drive->volumes = g_list_delete_link (drive->volumes, l); -+ emit_changed (drive); -+ } -+} -+ -+static GIcon * -+g_gdu_drive_get_icon (GDrive *_drive) -+{ -+ GGduDrive *drive = G_GDU_DRIVE (_drive); -+ return drive->icon != NULL ? g_object_ref (drive->icon) : NULL; -+} -+ -+static char * -+g_gdu_drive_get_name (GDrive *_drive) -+{ -+ GGduDrive *drive = G_GDU_DRIVE (_drive); -+ return g_strdup (drive->name); -+} -+ -+static GList * -+g_gdu_drive_get_volumes (GDrive *_drive) -+{ -+ GGduDrive *drive = G_GDU_DRIVE (_drive); -+ GList *l; -+ -+ l = g_list_copy (drive->volumes); -+ g_list_foreach (l, (GFunc) g_object_ref, NULL); -+ -+ return l; -+} -+ -+static gboolean -+g_gdu_drive_has_volumes (GDrive *_drive) -+{ -+ GGduDrive *drive = G_GDU_DRIVE (drive); -+ gboolean res; -+ -+ res = drive->volumes != NULL; -+ -+ return res; -+} -+ -+static gboolean -+g_gdu_drive_is_media_removable (GDrive *_drive) -+{ -+ GGduDrive *drive = G_GDU_DRIVE (_drive); -+ return drive->is_media_removable; -+} -+ -+static gboolean -+g_gdu_drive_has_media (GDrive *_drive) -+{ -+ GGduDrive *drive = G_GDU_DRIVE (_drive); -+ return drive->has_media; -+} -+ -+static gboolean -+g_gdu_drive_is_media_check_automatic (GDrive *_drive) -+{ -+ GGduDrive *drive = G_GDU_DRIVE (_drive); -+ return drive->is_media_check_automatic; -+} -+ -+static gboolean -+g_gdu_drive_can_eject (GDrive *_drive) -+{ -+ GGduDrive *drive = G_GDU_DRIVE (_drive); -+ return drive->can_eject; -+} -+ -+static gboolean -+g_gdu_drive_can_poll_for_media (GDrive *_drive) -+{ -+ GGduDrive *drive = G_GDU_DRIVE (_drive); -+ return drive->can_poll_for_media; -+} -+ -+static void -+eject_cb (GduDevice *device, -+ GError *error, -+ gpointer user_data) -+{ -+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data); -+ -+ if (error != NULL) -+ { -+ /* We could handle PolicyKit integration here but this action is allowed by default -+ * and this won't be needed when porting to PolicyKit 1.0 anyway -+ */ -+ g_simple_async_result_set_from_error (simple, error); -+ g_error_free (error); -+ } -+ -+ g_simple_async_result_complete (simple); -+ g_object_unref (simple); -+} -+ -+ -+static void -+g_gdu_drive_eject_do (GDrive *_drive, -+ GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data) -+{ -+ GGduDrive *drive = G_GDU_DRIVE (_drive); -+ GSimpleAsyncResult *simple; -+ GduDevice *device; -+ -+ device = gdu_presentable_get_device (drive->presentable); -+ if (device == NULL) -+ { -+ simple = g_simple_async_result_new_error (G_OBJECT (drive), -+ callback, -+ user_data, -+ G_IO_ERROR, -+ G_IO_ERROR_FAILED, -+ "Drive is activatable and not running"); -+ g_simple_async_result_complete_in_idle (simple); -+ g_object_unref (simple); -+ } -+ else -+ { -+ simple = g_simple_async_result_new (G_OBJECT (drive), -+ callback, -+ user_data, -+ NULL); -+ -+ gdu_device_op_drive_eject (device, eject_cb, simple); -+ g_object_unref (device); -+ } -+} -+ -+typedef struct { -+ GDrive *drive; -+ GAsyncReadyCallback callback; -+ gpointer user_data; -+ GCancellable *cancellable; -+ GMountUnmountFlags flags; -+ -+ GList *pending_mounts; -+} UnmountMountsOp; -+ -+static void -+free_unmount_mounts_op (UnmountMountsOp *data) -+{ -+ GList *l; -+ -+ for (l = data->pending_mounts; l != NULL; l = l->next) -+ { -+ GMount *mount = l->data; -+ g_object_unref (mount); -+ } -+ g_list_free (data->pending_mounts); -+} -+ -+static void _eject_unmount_mounts (UnmountMountsOp *data); -+ -+static void -+_eject_unmount_mounts_cb (GObject *source_object, -+ GAsyncResult *res, -+ gpointer user_data) -+{ -+ UnmountMountsOp *data = user_data; -+ GMount *mount = G_MOUNT (source_object); -+ GSimpleAsyncResult *simple; -+ GError *error = NULL; -+ -+ if (!g_mount_unmount_finish (mount, res, &error)) -+ { -+ /* make the error dialog more targeted to the drive.. unless the user has already seen a dialog */ -+ if (error->code != G_IO_ERROR_FAILED_HANDLED) -+ { -+ g_error_free (error); -+ error = g_error_new (G_IO_ERROR, G_IO_ERROR_BUSY, -+ _("Failed to eject media; one or more volumes on the media are busy.")); -+ } -+ -+ /* unmount failed; need to fail the whole eject operation */ -+ simple = g_simple_async_result_new_from_error (G_OBJECT (data->drive), -+ data->callback, -+ data->user_data, -+ error); -+ g_error_free (error); -+ g_simple_async_result_complete (simple); -+ g_object_unref (simple); -+ -+ free_unmount_mounts_op (data); -+ } -+ else -+ { -+ -+ /*g_warning ("successfully unmounted %p", mount);*/ -+ -+ /* move on to the next mount.. */ -+ _eject_unmount_mounts (data); -+ } -+ -+ g_object_unref (mount); -+} -+ -+static void -+_eject_unmount_mounts (UnmountMountsOp *data) -+{ -+ GMount *mount; -+ -+ if (data->pending_mounts == NULL) -+ { -+ -+ /*g_warning ("all pending mounts done; ejecting drive");*/ -+ -+ g_gdu_drive_eject_do (data->drive, -+ data->cancellable, -+ data->callback, -+ data->user_data); -+ -+ g_object_unref (data->drive); -+ g_free (data); -+ } -+ else -+ { -+ mount = data->pending_mounts->data; -+ data->pending_mounts = g_list_remove (data->pending_mounts, mount); -+ -+ /*g_warning ("unmounting %p", mount);*/ -+ -+ g_mount_unmount (mount, -+ data->flags, -+ data->cancellable, -+ _eject_unmount_mounts_cb, -+ data); -+ } -+} -+ -+static void -+g_gdu_drive_eject (GDrive *drive, -+ GMountUnmountFlags flags, -+ GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data) -+{ -+ GGduDrive *gdu_drive = G_GDU_DRIVE (drive); -+ UnmountMountsOp *data; -+ GList *l; -+ -+ /* first we need to go through all the volumes and unmount their assoicated mounts (if any) */ -+ -+ data = g_new0 (UnmountMountsOp, 1); -+ data->drive = g_object_ref (drive); -+ data->cancellable = cancellable; -+ data->callback = callback; -+ data->user_data = user_data; -+ data->flags = flags; -+ -+ for (l = gdu_drive->volumes; l != NULL; l = l->next) -+ { -+ GGduVolume *volume = l->data; -+ GMount *mount; -+ -+ mount = g_volume_get_mount (G_VOLUME (volume)); -+ if (mount != NULL && g_mount_can_unmount (mount)) -+ data->pending_mounts = g_list_prepend (data->pending_mounts, g_object_ref (mount)); -+ } -+ -+ _eject_unmount_mounts (data); -+} -+ -+static gboolean -+g_gdu_drive_eject_finish (GDrive *drive, -+ GAsyncResult *result, -+ GError **error) -+{ -+ return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error); -+} -+ -+static void -+poll_media_cb (GduDevice *device, -+ GError *error, -+ gpointer user_data) -+{ -+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data); -+ -+ if (error != NULL) -+ { -+ /* We could handle PolicyKit integration here but this action is allowed by default -+ * and this won't be needed when porting to PolicyKit 1.0 anyway -+ */ -+ g_simple_async_result_set_from_error (simple, error); -+ g_error_free (error); -+ } -+ -+ g_simple_async_result_complete (simple); -+ g_object_unref (simple); -+} -+ -+static void -+g_gdu_drive_poll_for_media (GDrive *_drive, -+ GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data) -+{ -+ GGduDrive *drive = G_GDU_DRIVE (_drive); -+ GSimpleAsyncResult *simple; -+ GduDevice *device; -+ -+ device = gdu_presentable_get_device (drive->presentable); -+ if (device == NULL) -+ { -+ simple = g_simple_async_result_new_error (G_OBJECT (drive), -+ callback, -+ user_data, -+ G_IO_ERROR, -+ G_IO_ERROR_FAILED, -+ "Device is not active"); -+ g_simple_async_result_complete_in_idle (simple); -+ g_object_unref (simple); -+ } -+ else -+ { -+ simple = g_simple_async_result_new (G_OBJECT (drive), -+ callback, -+ user_data, -+ NULL); -+ -+ gdu_device_op_drive_poll_media (device, poll_media_cb, simple); -+ g_object_unref (device); -+ } -+} -+ -+static gboolean -+g_gdu_drive_poll_for_media_finish (GDrive *drive, -+ GAsyncResult *result, -+ GError **error) -+{ -+ return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error); -+} -+ -+static char * -+g_gdu_drive_get_identifier (GDrive *_drive, -+ const char *kind) -+{ -+ GGduDrive *drive = G_GDU_DRIVE (_drive); -+ gchar *id; -+ -+ id = NULL; -+ -+ if (drive->device_file != NULL) -+ { -+ if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE) == 0) -+ id = g_strdup (drive->device_file); -+ } -+ -+ return id; -+} -+ -+static char ** -+g_gdu_drive_enumerate_identifiers (GDrive *_drive) -+{ -+ GGduDrive *drive = G_GDU_DRIVE (_drive); -+ GPtrArray *p; -+ -+ p = g_ptr_array_new (); -+ if (drive->device_file != NULL) -+ g_ptr_array_add (p, g_strdup (G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE)); -+ g_ptr_array_add (p, NULL); -+ -+ return (gchar **) g_ptr_array_free (p, FALSE); -+} -+ -+static void -+g_gdu_drive_drive_iface_init (GDriveIface *iface) -+{ -+ iface->get_name = g_gdu_drive_get_name; -+ iface->get_icon = g_gdu_drive_get_icon; -+ iface->has_volumes = g_gdu_drive_has_volumes; -+ iface->get_volumes = g_gdu_drive_get_volumes; -+ iface->is_media_removable = g_gdu_drive_is_media_removable; -+ iface->has_media = g_gdu_drive_has_media; -+ iface->is_media_check_automatic = g_gdu_drive_is_media_check_automatic; -+ iface->can_eject = g_gdu_drive_can_eject; -+ iface->can_poll_for_media = g_gdu_drive_can_poll_for_media; -+ iface->eject = g_gdu_drive_eject; -+ iface->eject_finish = g_gdu_drive_eject_finish; -+ iface->poll_for_media = g_gdu_drive_poll_for_media; -+ iface->poll_for_media_finish = g_gdu_drive_poll_for_media_finish; -+ iface->get_identifier = g_gdu_drive_get_identifier; -+ iface->enumerate_identifiers = g_gdu_drive_enumerate_identifiers; -+} -+ -+gboolean -+g_gdu_drive_has_device_file (GGduDrive *drive, -+ const gchar *device_file) -+{ -+ return g_strcmp0 (drive->device_file, device_file) == 0; -+} -+ -+gboolean -+g_gdu_drive_has_presentable (GGduDrive *drive, -+ GduPresentable *presentable) -+{ -+ return gdu_presentable_get_id (drive->presentable) == gdu_presentable_get_id (presentable); -+} -+ -+time_t -+g_gdu_drive_get_time_of_last_media_insertion (GGduDrive *drive) -+{ -+ return drive->time_of_last_media_insertion; -+} -+ -+GduPresentable * -+g_gdu_drive_get_presentable (GGduDrive *drive) -+{ -+ return drive->presentable; -+} -diff --git a/monitor/gdu/ggdudrive.h b/monitor/gdu/ggdudrive.h -new file mode 100644 -index 0000000..e182c29 ---- /dev/null -+++ b/monitor/gdu/ggdudrive.h -@@ -0,0 +1,69 @@ -+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -+/* gvfs - extensions for gio -+ * -+ * Copyright (C) 2006-2009 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., 59 Temple Place, Suite 330, -+ * Boston, MA 02111-1307, USA. -+ * -+ * Author: David Zeuthen -+ */ -+ -+#ifndef __G_GDU_DRIVE_H__ -+#define __G_GDU_DRIVE_H__ -+ -+#include -+#include -+ -+#include "ggduvolumemonitor.h" -+ -+G_BEGIN_DECLS -+ -+#define G_TYPE_GDU_DRIVE (g_gdu_drive_get_type ()) -+#define G_GDU_DRIVE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_GDU_DRIVE, GGduDrive)) -+#define G_GDU_DRIVE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_GDU_DRIVE, GGduDriveClass)) -+#define G_IS_GDU_DRIVE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_GDU_DRIVE)) -+#define G_IS_GDU_DRIVE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_GDU_DRIVE)) -+ -+typedef struct _GGduDriveClass GGduDriveClass; -+ -+struct _GGduDriveClass { -+ GObjectClass parent_class; -+}; -+ -+GType g_gdu_drive_get_type (void) G_GNUC_CONST; -+ -+GGduDrive *g_gdu_drive_new (GVolumeMonitor *volume_monitor, -+ GduPresentable *presentable); -+void g_gdu_drive_set_volume (GGduDrive *drive, -+ GGduVolume *volume); -+void g_gdu_drive_unset_volume (GGduDrive *drive, -+ GGduVolume *volume); -+void g_gdu_drive_disconnected (GGduDrive *drive); -+gboolean g_gdu_drive_has_device_file (GGduDrive *drive, -+ const gchar *device_file); -+time_t g_gdu_drive_get_time_of_last_media_insertion (GGduDrive *drive); -+ -+gboolean g_gdu_drive_has_presentable (GGduDrive *drive, -+ GduPresentable *presentable); -+ -+GduPresentable *g_gdu_drive_get_presentable (GGduDrive *drive); -+ -+ -+char * _drive_get_icon (GduDevice *d); -+ -+G_END_DECLS -+ -+#endif /* __G_GDU_DRIVE_H__ */ -diff --git a/monitor/gdu/ggdumount.c b/monitor/gdu/ggdumount.c -new file mode 100644 -index 0000000..27c22d9 ---- /dev/null -+++ b/monitor/gdu/ggdumount.c -@@ -0,0 +1,958 @@ -+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -+/* gvfs - extensions for gio -+ * -+ * Copyright (C) 2006-2009 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., 59 Temple Place, Suite 330, -+ * Boston, MA 02111-1307, USA. -+ * -+ * Author: David Zeuthen -+ */ -+ -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include -+ -+#include "ggduvolumemonitor.h" -+#include "ggdumount.h" -+#include "ggduvolume.h" -+ -+struct _GGduMount -+{ -+ GObject parent; -+ -+ GVolumeMonitor *volume_monitor; /* owned by volume monitor */ -+ GGduVolume *volume; /* owned by volume monitor */ -+ -+ /* the following members need to be set upon construction */ -+ GFile *root; -+ GIcon *icon; -+ gchar *name; -+ gchar *uuid; -+ gchar *device_file; -+ gchar *mount_path; -+ gboolean can_unmount; -+ -+ gchar *mount_entry_name; -+ GIcon *mount_entry_icon; -+ -+ gboolean is_burn_mount; -+ -+ GIcon *autorun_icon; -+ gboolean searched_for_autorun; -+ -+ gchar *xdg_volume_info_name; -+ GIcon *xdg_volume_info_icon; -+ gboolean searched_for_xdg_volume_info; -+}; -+ -+static gboolean update_mount (GGduMount *mount); -+ -+static void g_gdu_mount_mount_iface_init (GMountIface *iface); -+ -+G_DEFINE_TYPE_EXTENDED (GGduMount, g_gdu_mount, G_TYPE_OBJECT, 0, -+ G_IMPLEMENT_INTERFACE (G_TYPE_MOUNT, -+ g_gdu_mount_mount_iface_init)) -+ -+static void -+volume_changed (GVolume *volume, -+ gpointer user_data); -+ -+static void -+g_gdu_mount_finalize (GObject *object) -+{ -+ GGduMount *mount; -+ -+ mount = G_GDU_MOUNT (object); -+ -+ if (mount->volume != NULL) -+ { -+ g_signal_handlers_disconnect_by_func (mount->volume, volume_changed, mount); -+ g_gdu_volume_unset_mount (mount->volume, mount); -+ } -+ -+ if (mount->root != NULL) -+ g_object_unref (mount->root); -+ if (mount->icon != NULL) -+ g_object_unref (mount->icon); -+ g_free (mount->name); -+ g_free (mount->uuid); -+ g_free (mount->device_file); -+ g_free (mount->mount_path); -+ -+ g_free (mount->mount_entry_name); -+ if (mount->mount_entry_icon != NULL) -+ g_object_unref (mount->mount_entry_icon); -+ -+ if (mount->autorun_icon != NULL) -+ g_object_unref (mount->autorun_icon); -+ -+ g_free (mount->xdg_volume_info_name); -+ if (mount->xdg_volume_info_icon != NULL) -+ g_object_unref (mount->xdg_volume_info_icon); -+ -+ if (G_OBJECT_CLASS (g_gdu_mount_parent_class)->finalize) -+ (*G_OBJECT_CLASS (g_gdu_mount_parent_class)->finalize) (object); -+} -+ -+static void -+g_gdu_mount_class_init (GGduMountClass *klass) -+{ -+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass); -+ -+ gobject_class->finalize = g_gdu_mount_finalize; -+} -+ -+static void -+g_gdu_mount_init (GGduMount *mount) -+{ -+} -+ -+static void -+emit_changed (GGduMount *mount) -+{ -+ g_signal_emit_by_name (mount, "changed"); -+ g_signal_emit_by_name (mount->volume_monitor, "mount_changed", mount); -+} -+ -+static void -+got_autorun_info_cb (GObject *source_object, -+ GAsyncResult *res, -+ gpointer user_data) -+{ -+ GGduMount *mount = G_GDU_MOUNT (user_data); -+ -+ mount->autorun_icon = g_vfs_mount_info_query_autorun_info_finish (G_FILE (source_object), -+ res, -+ NULL); -+ -+ if (update_mount (mount)) -+ emit_changed (mount); -+ -+ g_object_unref (mount); -+} -+ -+static void -+got_xdg_volume_info_cb (GObject *source_object, -+ GAsyncResult *res, -+ gpointer user_data) -+{ -+ GGduMount *mount = G_GDU_MOUNT (user_data); -+ -+ mount->xdg_volume_info_icon = g_vfs_mount_info_query_xdg_volume_info_finish (G_FILE (source_object), -+ res, -+ &(mount->xdg_volume_info_name), -+ NULL); -+ if (update_mount (mount)) -+ emit_changed (mount); -+ -+ g_object_unref (mount); -+} -+ -+static gboolean -+update_mount (GGduMount *mount) -+{ -+ gboolean changed; -+ gboolean old_can_unmount; -+ gchar *old_name; -+ GIcon *old_icon; -+ -+ /* save old values */ -+ old_can_unmount = mount->can_unmount; -+ old_name = g_strdup (mount->name); -+ old_icon = mount->icon != NULL ? g_object_ref (mount->icon) : NULL; -+ -+ /* in with the new */ -+ if (mount->volume != NULL) -+ { -+ mount->can_unmount = TRUE; -+ -+ if (mount->icon != NULL) -+ g_object_unref (mount->icon); -+ -+ /* order of preference: xdg, autorun, probed */ -+ if (mount->xdg_volume_info_icon != NULL) -+ mount->icon = g_object_ref (mount->xdg_volume_info_icon); -+ else if (mount->autorun_icon != NULL) -+ mount->icon = g_object_ref (mount->autorun_icon); -+ else -+ mount->icon = g_volume_get_icon (G_VOLUME (mount->volume)); -+ -+ g_free (mount->name); -+ -+ /* order of preference : xdg, probed */ -+ if (mount->xdg_volume_info_name != NULL) -+ mount->name = g_strdup (mount->xdg_volume_info_name); -+ else -+ mount->name = g_volume_get_name (G_VOLUME (mount->volume)); -+ } -+ else -+ { -+ mount->can_unmount = TRUE; -+ -+ if (mount->icon != NULL) -+ g_object_unref (mount->icon); -+ -+ /* order of preference: xdg, autorun, probed */ -+ if (mount->xdg_volume_info_icon != NULL) -+ mount->icon = g_object_ref (mount->xdg_volume_info_icon); -+ else if (mount->autorun_icon != NULL) -+ mount->icon = g_object_ref (mount->autorun_icon); -+ else -+ mount->icon = mount->mount_entry_icon != NULL ? g_object_ref (mount->mount_entry_icon) : NULL; -+ -+ g_free (mount->name); -+ -+ /* order of preference : xdg, probed */ -+ if (mount->xdg_volume_info_name != NULL) -+ mount->name = g_strdup (mount->xdg_volume_info_name); -+ else -+ mount->name = g_strdup (mount->mount_entry_name); -+ } -+ -+ /* compute whether something changed */ -+ changed = !((old_can_unmount == mount->can_unmount) && -+ (g_strcmp0 (old_name, mount->name) == 0) && -+ g_icon_equal (old_icon, mount->icon) -+ ); -+ -+ /* free old values */ -+ g_free (old_name); -+ if (old_icon != NULL) -+ g_object_unref (old_icon); -+ -+ /*g_debug ("in update_mount(), changed=%d", changed);*/ -+ -+ /* search for .xdg-volume-info */ -+ if (!mount->searched_for_xdg_volume_info) -+ { -+ mount->searched_for_xdg_volume_info = TRUE; -+ g_vfs_mount_info_query_xdg_volume_info (mount->root, -+ NULL, -+ got_xdg_volume_info_cb, -+ g_object_ref (mount)); -+ } -+ -+ /* search for autorun.inf */ -+ if (!mount->searched_for_autorun) -+ { -+ mount->searched_for_autorun = TRUE; -+ g_vfs_mount_info_query_autorun_info (mount->root, -+ NULL, -+ got_autorun_info_cb, -+ g_object_ref (mount)); -+ } -+ -+ return changed; -+} -+ -+static void -+volume_changed (GVolume *volume, -+ gpointer user_data) -+{ -+ GGduMount *mount = G_GDU_MOUNT (user_data); -+ -+ if (update_mount (mount)) -+ emit_changed (mount); -+} -+ -+GGduMount * -+g_gdu_mount_new (GVolumeMonitor *volume_monitor, -+ GUnixMountEntry *mount_entry, -+ GGduVolume *volume) -+{ -+ GGduMount *mount; -+ -+ mount = NULL; -+ -+ /* Ignore internal mounts unless there's a volume */ -+ if (volume == NULL && (mount_entry != NULL && !g_unix_mount_guess_should_display (mount_entry))) -+ goto out; -+ -+ mount = g_object_new (G_TYPE_GDU_MOUNT, NULL); -+ mount->volume_monitor = volume_monitor; -+ g_object_add_weak_pointer (G_OBJECT (volume_monitor), (gpointer) &(mount->volume_monitor)); -+ -+ if (mount_entry != NULL) -+ { -+ /* No ref on GUnixMountEntry so save values for later use */ -+ mount->mount_entry_name = g_unix_mount_guess_name (mount_entry); -+ mount->mount_entry_icon = g_unix_mount_guess_icon (mount_entry); -+ mount->device_file = g_strdup (g_unix_mount_get_device_path (mount_entry)); -+ mount->mount_path = g_strdup (g_unix_mount_get_mount_path (mount_entry)); -+ mount->root = g_file_new_for_path (mount->mount_path); -+ } -+ else -+ { -+ /* burn:/// mount (the only mounts we support with mount_entry == NULL) */ -+ mount->device_file = NULL; -+ mount->mount_path = NULL; -+ mount->root = g_file_new_for_uri ("burn:///"); -+ mount->is_burn_mount = TRUE; -+ } -+ -+ /* need to set the volume only when the mount is fully constructed */ -+ mount->volume = volume; -+ if (mount->volume != NULL) -+ { -+ g_gdu_volume_set_mount (volume, mount); -+ /* this is for piggy backing on the name and icon of the associated volume */ -+ g_signal_connect (mount->volume, "changed", G_CALLBACK (volume_changed), mount); -+ } -+ -+ update_mount (mount); -+ -+ out: -+ -+ return mount; -+} -+ -+void -+g_gdu_mount_unmounted (GGduMount *mount) -+{ -+ if (mount->volume != NULL) -+ { -+ g_gdu_volume_unset_mount (mount->volume, mount); -+ g_signal_handlers_disconnect_by_func (mount->volume, volume_changed, mount); -+ mount->volume = NULL; -+ emit_changed (mount); -+ } -+} -+ -+void -+g_gdu_mount_unset_volume (GGduMount *mount, -+ GGduVolume *volume) -+{ -+ if (mount->volume == volume) -+ { -+ g_signal_handlers_disconnect_by_func (mount->volume, volume_changed, mount); -+ mount->volume = NULL; -+ emit_changed (mount); -+ } -+} -+ -+static GFile * -+g_gdu_mount_get_root (GMount *_mount) -+{ -+ GGduMount *mount = G_GDU_MOUNT (_mount); -+ return mount->root != NULL ? g_object_ref (mount->root) : NULL; -+} -+ -+static GIcon * -+g_gdu_mount_get_icon (GMount *_mount) -+{ -+ GGduMount *mount = G_GDU_MOUNT (_mount); -+ return mount->icon != NULL ? g_object_ref (mount->icon) : NULL; -+} -+ -+static gchar * -+g_gdu_mount_get_uuid (GMount *_mount) -+{ -+ GGduMount *mount = G_GDU_MOUNT (_mount); -+ return g_strdup (mount->uuid); -+} -+ -+static gchar * -+g_gdu_mount_get_name (GMount *_mount) -+{ -+ GGduMount *mount = G_GDU_MOUNT (_mount); -+ return g_strdup (mount->name); -+} -+ -+gboolean -+g_gdu_mount_has_uuid (GGduMount *_mount, -+ const gchar *uuid) -+{ -+ GGduMount *mount = G_GDU_MOUNT (_mount); -+ return g_strcmp0 (mount->uuid, uuid) == 0; -+} -+ -+gboolean -+g_gdu_mount_has_mount_path (GGduMount *_mount, -+ const gchar *mount_path) -+{ -+ GGduMount *mount = G_GDU_MOUNT (_mount); -+ return g_strcmp0 (mount->mount_path, mount_path) == 0; -+} -+ -+static GDrive * -+g_gdu_mount_get_drive (GMount *_mount) -+{ -+ GGduMount *mount = G_GDU_MOUNT (_mount); -+ GDrive *drive; -+ -+ drive = NULL; -+ if (mount->volume != NULL) -+ drive = g_volume_get_drive (G_VOLUME (mount->volume)); -+ -+ return drive; -+} -+ -+static GVolume * -+g_gdu_mount_get_volume (GMount *_mount) -+{ -+ GGduMount *mount = G_GDU_MOUNT (_mount); -+ GVolume *volume; -+ -+ volume = NULL; -+ if (mount->volume) -+ volume = G_VOLUME (g_object_ref (mount->volume)); -+ -+ return volume; -+} -+ -+static gboolean -+g_gdu_mount_can_unmount (GMount *_mount) -+{ -+ GGduMount *mount = G_GDU_MOUNT (_mount); -+ return mount->can_unmount; -+} -+ -+static gboolean -+g_gdu_mount_can_eject (GMount *_mount) -+{ -+ GGduMount *mount = G_GDU_MOUNT (_mount); -+ GDrive *drive; -+ gboolean can_eject; -+ -+ can_eject = FALSE; -+ if (mount->volume != NULL) -+ { -+ drive = g_volume_get_drive (G_VOLUME (mount->volume)); -+ if (drive != NULL) -+ can_eject = g_drive_can_eject (drive); -+ } -+ -+ return can_eject; -+} -+ -+/* ---------------------------------------------------------------------------------------------------- */ -+ -+typedef struct { -+ GMount *mount; -+ GAsyncReadyCallback callback; -+ gpointer user_data; -+ GCancellable *cancellable; -+ int error_fd; -+ GIOChannel *error_channel; -+ guint error_channel_source_id; -+ GString *error_string; -+} UnmountEjectOp; -+ -+static void -+eject_unmount_cb (GPid pid, gint status, gpointer user_data) -+{ -+ UnmountEjectOp *data = user_data; -+ GSimpleAsyncResult *simple; -+ -+ if (WEXITSTATUS (status) != 0) -+ { -+ GError *error; -+ error = g_error_new_literal (G_IO_ERROR, -+ G_IO_ERROR_FAILED, -+ data->error_string->str); -+ simple = g_simple_async_result_new_from_error (G_OBJECT (data->mount), -+ data->callback, -+ data->user_data, -+ error); -+ g_error_free (error); -+ } -+ else -+ { -+ simple = g_simple_async_result_new (G_OBJECT (data->mount), -+ data->callback, -+ data->user_data, -+ NULL); -+ } -+ -+ g_simple_async_result_complete (simple); -+ g_object_unref (simple); -+ -+ g_source_remove (data->error_channel_source_id); -+ g_io_channel_unref (data->error_channel); -+ g_string_free (data->error_string, TRUE); -+ close (data->error_fd); -+ g_spawn_close_pid (pid); -+ g_free (data); -+} -+ -+static gboolean -+eject_unmount_read_error (GIOChannel *channel, -+ GIOCondition condition, -+ gpointer user_data) -+{ -+ UnmountEjectOp *data = user_data; -+ gchar buf[BUFSIZ]; -+ gsize bytes_read; -+ GError *error; -+ GIOStatus status; -+ -+ error = NULL; -+read: -+ status = g_io_channel_read_chars (channel, buf, sizeof (buf), &bytes_read, &error); -+ if (status == G_IO_STATUS_NORMAL) -+ { -+ g_string_append_len (data->error_string, buf, bytes_read); -+ if (bytes_read == sizeof (buf)) -+ goto read; -+ } -+ else if (status == G_IO_STATUS_EOF) -+ g_string_append_len (data->error_string, buf, bytes_read); -+ else if (status == G_IO_STATUS_ERROR) -+ { -+ if (data->error_string->len > 0) -+ g_string_append (data->error_string, "\n"); -+ -+ g_string_append (data->error_string, error->message); -+ g_error_free (error); -+ return FALSE; -+ } -+ -+ return TRUE; -+} -+ -+static void -+eject_unmount_do (GMount *mount, -+ GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data, -+ char **argv) -+{ -+ UnmountEjectOp *data; -+ GPid child_pid; -+ GError *error; -+ -+ data = g_new0 (UnmountEjectOp, 1); -+ data->mount = mount; -+ data->callback = callback; -+ data->user_data = user_data; -+ data->cancellable = cancellable; -+ -+ error = NULL; -+ if (!g_spawn_async_with_pipes (NULL, /* working dir */ -+ argv, -+ NULL, /* envp */ -+ G_SPAWN_DO_NOT_REAP_CHILD|G_SPAWN_SEARCH_PATH, -+ NULL, /* child_setup */ -+ NULL, /* user_data for child_setup */ -+ &child_pid, -+ NULL, /* standard_input */ -+ NULL, /* standard_output */ -+ &(data->error_fd), -+ &error)) { -+ g_assert (error != NULL); -+ goto handle_error; -+ } -+ -+ data->error_string = g_string_new (""); -+ -+ data->error_channel = g_io_channel_unix_new (data->error_fd); -+ g_io_channel_set_flags (data->error_channel, G_IO_FLAG_NONBLOCK, &error); -+ if (error != NULL) -+ goto handle_error; -+ -+ data->error_channel_source_id = g_io_add_watch (data->error_channel, G_IO_IN, eject_unmount_read_error, data); -+ g_child_watch_add (child_pid, eject_unmount_cb, data); -+ -+handle_error: -+ -+ if (error != NULL) -+ { -+ GSimpleAsyncResult *simple; -+ simple = g_simple_async_result_new_from_error (G_OBJECT (data->mount), -+ data->callback, -+ data->user_data, -+ error); -+ g_simple_async_result_complete (simple); -+ g_object_unref (simple); -+ -+ if (data->error_string != NULL) -+ g_string_free (data->error_string, TRUE); -+ -+ if (data->error_channel != NULL) -+ g_io_channel_unref (data->error_channel); -+ -+ g_error_free (error); -+ g_free (data); -+ } -+} -+ -+/* ---------------------------------------------------------------------------------------------------- */ -+static void -+luks_lock_cb (GduDevice *device, -+ GError *error, -+ gpointer user_data) -+{ -+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data); -+ -+ if (error != NULL) -+ { -+ /* We could handle PolicyKit integration here but this action is allowed by default -+ * and this won't be needed when porting to PolicyKit 1.0 anyway -+ */ -+ g_simple_async_result_set_from_error (simple, error); -+ g_error_free (error); -+ } -+ -+ g_simple_async_result_complete (simple); -+ g_object_unref (simple); -+} -+ -+static void -+unmount_cb (GduDevice *device, -+ GError *error, -+ gpointer user_data) -+{ -+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data); -+ -+ if (error != NULL) -+ { -+ /* We could handle PolicyKit integration here but this action is allowed by default -+ * and this won't be needed when porting to PolicyKit 1.0 anyway -+ */ -+ g_simple_async_result_set_from_error (simple, error); -+ g_error_free (error); -+ g_simple_async_result_complete (simple); -+ g_object_unref (simple); -+ goto out; -+ } -+ -+ /* if volume is a cleartext LUKS block device, then also lock this one */ -+ if (gdu_device_is_luks_cleartext (device)) -+ { -+ const gchar *luks_cleartext_slave_object_path; -+ GduDevice *luks_cleartext_slave; -+ GduPool *pool; -+ -+ luks_cleartext_slave_object_path = gdu_device_luks_cleartext_get_slave (device); -+ if (luks_cleartext_slave_object_path == NULL) -+ { -+ g_simple_async_result_set_error (simple, -+ G_IO_ERROR, -+ G_IO_ERROR_FAILED, -+ "Cannot get LUKS cleartext slave"); -+ g_simple_async_result_complete (simple); -+ g_object_unref (simple); -+ goto out; -+ } -+ -+ pool = gdu_device_get_pool (device); -+ luks_cleartext_slave = gdu_pool_get_by_object_path (pool, luks_cleartext_slave_object_path); -+ g_object_unref (pool); -+ -+ if (luks_cleartext_slave == NULL) -+ { -+ g_simple_async_result_set_error (simple, -+ G_IO_ERROR, -+ G_IO_ERROR_FAILED, -+ "Cannot get LUKS cleartext slave"); -+ g_simple_async_result_complete (simple); -+ g_object_unref (simple); -+ goto out; -+ } -+ -+ gdu_device_op_luks_lock (luks_cleartext_slave, -+ luks_lock_cb, -+ simple); -+ -+ g_object_unref (luks_cleartext_slave); -+ goto out; -+ } -+ -+ g_simple_async_result_complete (simple); -+ g_object_unref (simple); -+ -+ out: -+ ; -+} -+ -+static void -+g_gdu_mount_unmount (GMount *_mount, -+ GMountUnmountFlags flags, -+ GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data) -+{ -+ GGduMount *mount = G_GDU_MOUNT (_mount); -+ GSimpleAsyncResult *simple; -+ -+ if (mount->volume == NULL) -+ { -+ gchar *argv[] = {"umount", NULL, NULL}; -+ -+ /* TODO: honor flags */ -+ -+ if (mount->mount_path != NULL) -+ argv[1] = mount->mount_path; -+ else -+ argv[1] = mount->device_file; -+ -+ eject_unmount_do (_mount, cancellable, callback, user_data, argv); -+ } -+ else -+ { -+ simple = g_simple_async_result_new (G_OBJECT (mount), -+ callback, -+ user_data, -+ NULL); -+ -+ if (mount->is_burn_mount) -+ { -+ /* burn mounts are really never mounted... */ -+ g_simple_async_result_complete (simple); -+ g_object_unref (simple); -+ } -+ else -+ { -+ GduDevice *device; -+ GduPresentable *volume; -+ -+ /* TODO: honor flags */ -+ -+ volume = g_gdu_volume_get_presentable_with_cleartext (mount->volume); -+ device = gdu_presentable_get_device (volume); -+ -+ gdu_device_op_filesystem_unmount (device, unmount_cb, simple); -+ -+ g_object_unref (device); -+ } -+ } -+} -+ -+static gboolean -+g_gdu_mount_unmount_finish (GMount *mount, -+ GAsyncResult *result, -+ GError **error) -+{ -+ return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error); -+} -+ -+typedef struct { -+ GObject *object; -+ GAsyncReadyCallback callback; -+ gpointer user_data; -+} EjectWrapperOp; -+ -+static void -+eject_wrapper_callback (GObject *source_object, -+ GAsyncResult *res, -+ gpointer user_data) -+{ -+ EjectWrapperOp *data = user_data; -+ data->callback (data->object, res, data->user_data); -+ g_object_unref (data->object); -+ g_free (data); -+} -+ -+static void -+g_gdu_mount_eject (GMount *mount, -+ GMountUnmountFlags flags, -+ GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data) -+{ -+ GGduMount *gdu_mount = G_GDU_MOUNT (mount); -+ GDrive *drive; -+ -+ drive = NULL; -+ if (gdu_mount->volume != NULL) -+ drive = g_volume_get_drive (G_VOLUME (gdu_mount->volume)); -+ -+ if (drive != NULL) -+ { -+ EjectWrapperOp *data; -+ data = g_new0 (EjectWrapperOp, 1); -+ data->object = g_object_ref (mount); -+ data->callback = callback; -+ data->user_data = user_data; -+ g_drive_eject (drive, flags, cancellable, eject_wrapper_callback, data); -+ g_object_unref (drive); -+ } -+ else -+ { -+ GSimpleAsyncResult *simple; -+ simple = g_simple_async_result_new_error (G_OBJECT (mount), -+ callback, -+ user_data, -+ G_IO_ERROR, -+ G_IO_ERROR_FAILED, -+ _("Operation not supported by backend")); -+ g_simple_async_result_complete (simple); -+ g_object_unref (simple); -+ } -+ -+} -+ -+static gboolean -+g_gdu_mount_eject_finish (GMount *_mount, -+ GAsyncResult *result, -+ GError **error) -+{ -+ GGduMount *mount = G_GDU_MOUNT (_mount); -+ GDrive *drive; -+ gboolean res; -+ -+ res = TRUE; -+ -+ drive = NULL; -+ if (mount->volume != NULL) -+ drive = g_volume_get_drive (G_VOLUME (mount->volume)); -+ -+ if (drive != NULL) -+ { -+ res = g_drive_eject_finish (drive, result, error); -+ g_object_unref (drive); -+ } -+ else -+ { -+ g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error); -+ res = FALSE; -+ } -+ -+ return res; -+} -+ -+/* TODO: handle force_rescan */ -+static gchar ** -+g_gdu_mount_guess_content_type_sync (GMount *_mount, -+ gboolean force_rescan, -+ GCancellable *cancellable, -+ GError **error) -+{ -+ GGduMount *mount = G_GDU_MOUNT (_mount); -+ const gchar *disc_type; -+ char **x_content_types; -+ GPtrArray *p; -+ gchar **result; -+ GduDevice *device; -+ guint n; -+ -+ p = g_ptr_array_new (); -+ -+ device = NULL; -+ if (mount->volume != NULL) -+ { -+ GduPresentable *presentable; -+ presentable = g_gdu_volume_get_presentable_with_cleartext (mount->volume); -+ device = gdu_presentable_get_device (presentable); -+ } -+ -+ /* doesn't make sense to probe blank discs - look at the disc type instead */ -+ if (device != NULL && gdu_device_optical_disc_get_is_blank (device)) -+ { -+ disc_type = gdu_device_drive_get_media (device); -+ if (disc_type != NULL) -+ { -+ if (g_str_has_prefix (disc_type, "optical_dvd")) -+ g_ptr_array_add (p, g_strdup ("x-content/blank-dvd")); -+ else if (g_str_has_prefix (disc_type, "optical_hddvd")) -+ g_ptr_array_add (p, g_strdup ("x-content/blank-hddvd")); -+ else if (g_str_has_prefix (disc_type, "optical_bd")) -+ g_ptr_array_add (p, g_strdup ("x-content/blank-bd")); -+ else -+ g_ptr_array_add (p, g_strdup ("x-content/blank-cd")); /* assume CD */ -+ } -+ } -+ else -+ { -+ /* sniff content type */ -+ x_content_types = g_content_type_guess_for_tree (mount->root); -+ if (x_content_types != NULL) -+ { -+ for (n = 0; x_content_types[n] != NULL; n++) -+ g_ptr_array_add (p, g_strdup (x_content_types[n])); -+ g_strfreev (x_content_types); -+ } -+ } -+ -+ if (p->len == 0) -+ { -+ result = NULL; -+ g_ptr_array_free (p, TRUE); -+ } -+ else -+ { -+ g_ptr_array_add (p, NULL); -+ result = (char **) g_ptr_array_free (p, FALSE); -+ } -+ -+ if (device != NULL) -+ g_object_unref (device); -+ -+ return result; -+} -+ -+/* since we're an out-of-process volume monitor we'll just do this sync */ -+static void -+g_gdu_mount_guess_content_type (GMount *mount, -+ gboolean force_rescan, -+ GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data) -+{ -+ GSimpleAsyncResult *simple; -+ -+ /* TODO: handle force_rescan */ -+ simple = g_simple_async_result_new (G_OBJECT (mount), -+ callback, -+ user_data, -+ NULL); -+ g_simple_async_result_complete (simple); -+ g_object_unref (simple); -+} -+ -+static gchar ** -+g_gdu_mount_guess_content_type_finish (GMount *mount, -+ GAsyncResult *result, -+ GError **error) -+{ -+ return g_gdu_mount_guess_content_type_sync (mount, FALSE, NULL, error); -+} -+ -+static void -+g_gdu_mount_mount_iface_init (GMountIface *iface) -+{ -+ iface->get_root = g_gdu_mount_get_root; -+ iface->get_name = g_gdu_mount_get_name; -+ iface->get_icon = g_gdu_mount_get_icon; -+ iface->get_uuid = g_gdu_mount_get_uuid; -+ iface->get_drive = g_gdu_mount_get_drive; -+ iface->get_volume = g_gdu_mount_get_volume; -+ iface->can_unmount = g_gdu_mount_can_unmount; -+ iface->can_eject = g_gdu_mount_can_eject; -+ iface->unmount = g_gdu_mount_unmount; -+ iface->unmount_finish = g_gdu_mount_unmount_finish; -+ iface->eject = g_gdu_mount_eject; -+ iface->eject_finish = g_gdu_mount_eject_finish; -+ iface->guess_content_type = g_gdu_mount_guess_content_type; -+ iface->guess_content_type_finish = g_gdu_mount_guess_content_type_finish; -+ iface->guess_content_type_sync = g_gdu_mount_guess_content_type_sync; -+} -+ -+gboolean -+g_gdu_mount_has_volume (GGduMount *mount, -+ GGduVolume *volume) -+{ -+ return mount->volume == volume; -+} -diff --git a/monitor/gdu/ggdumount.h b/monitor/gdu/ggdumount.h -new file mode 100644 -index 0000000..62a19d8 ---- /dev/null -+++ b/monitor/gdu/ggdumount.h -@@ -0,0 +1,64 @@ -+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -+/* gvfs - extensions for gio -+ * -+ * Copyright (C) 2006-2009 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., 59 Temple Place, Suite 330, -+ * Boston, MA 02111-1307, USA. -+ * -+ * Author: David Zeuthen -+ */ -+ -+#ifndef __G_GDU_MOUNT_H__ -+#define __G_GDU_MOUNT_H__ -+ -+#include -+#include -+ -+#include "ggduvolumemonitor.h" -+ -+G_BEGIN_DECLS -+ -+#define G_TYPE_GDU_MOUNT (g_gdu_mount_get_type ()) -+#define G_GDU_MOUNT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_GDU_MOUNT, GGduMount)) -+#define G_GDU_MOUNT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_GDU_MOUNT, GGduMountClass)) -+#define G_IS_GDU_MOUNT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_GDU_MOUNT)) -+#define G_IS_GDU_MOUNT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_GDU_MOUNT)) -+ -+typedef struct _GGduMountClass GGduMountClass; -+ -+struct _GGduMountClass { -+ GObjectClass parent_class; -+}; -+ -+GType g_gdu_mount_get_type (void) G_GNUC_CONST; -+ -+GGduMount * g_gdu_mount_new (GVolumeMonitor *volume_monitor, -+ GUnixMountEntry *mount_entry, -+ GGduVolume *volume); -+gboolean g_gdu_mount_has_mount_path (GGduMount *mount, -+ const gchar *mount_path); -+gboolean g_gdu_mount_has_uuid (GGduMount *mount, -+ const gchar *uuid); -+void g_gdu_mount_unset_volume (GGduMount *mount, -+ GGduVolume *volume); -+void g_gdu_mount_unmounted (GGduMount *mount); -+ -+gboolean g_gdu_mount_has_volume (GGduMount *mount, -+ GGduVolume *volume); -+ -+G_END_DECLS -+ -+#endif /* __G_GDU_MOUNT_H__ */ -diff --git a/monitor/gdu/ggduvolume.c b/monitor/gdu/ggduvolume.c -new file mode 100644 -index 0000000..b540325 ---- /dev/null -+++ b/monitor/gdu/ggduvolume.c -@@ -0,0 +1,1408 @@ -+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -+/* gvfs - extensions for gio -+ * -+ * Copyright (C) 2006-2009 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., 59 Temple Place, Suite 330, -+ * Boston, MA 02111-1307, USA. -+ * -+ * Author: David Zeuthen -+ */ -+ -+#include -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "ggdudrive.h" -+#include "ggduvolume.h" -+#include "ggdumount.h" -+ -+#include "polkit.h" -+ -+typedef struct MountOpData MountOpData; -+ -+static void cancel_pending_mount_op (MountOpData *data); -+ -+struct _GGduVolume -+{ -+ GObject parent; -+ -+ GVolumeMonitor *volume_monitor; /* owned by volume monitor */ -+ GGduMount *mount; /* owned by volume monitor */ -+ GGduDrive *drive; /* owned by volume monitor */ -+ -+ GduVolume *gdu_volume; -+ -+ /* if the volume is encrypted, this is != NULL when unlocked */ -+ GduVolume *cleartext_gdu_volume; -+ -+ /* If a mount operation is in progress, then pending_mount_op is != NULL. This -+ * is used to cancel the operation to make possible authentication dialogs go -+ * away. -+ */ -+ MountOpData *pending_mount_op; -+ -+ /* the following members need to be set upon construction */ -+ GIcon *icon; -+ GFile *activation_root; -+ gchar *name; -+ gchar *device_file; -+ gchar *uuid; -+ gboolean can_mount; -+ gboolean should_automount; -+}; -+ -+static void g_gdu_volume_volume_iface_init (GVolumeIface *iface); -+ -+G_DEFINE_TYPE_EXTENDED (GGduVolume, g_gdu_volume, G_TYPE_OBJECT, 0, -+ G_IMPLEMENT_INTERFACE (G_TYPE_VOLUME, -+ g_gdu_volume_volume_iface_init)) -+ -+static void gdu_volume_changed (GduPresentable *presentable, -+ GGduVolume *volume); -+static void gdu_volume_job_changed (GduPresentable *presentable, -+ GGduVolume *volume); -+ -+static void gdu_cleartext_volume_removed (GduPresentable *presentable, -+ GGduVolume *volume); -+static void gdu_cleartext_volume_changed (GduPresentable *presentable, -+ GGduVolume *volume); -+static void gdu_cleartext_volume_job_changed (GduPresentable *presentable, -+ GGduVolume *volume); -+ -+static void mount_with_mount_operation (MountOpData *data); -+ -+static void -+g_gdu_volume_finalize (GObject *object) -+{ -+ GGduVolume *volume; -+ -+ volume = G_GDU_VOLUME (object); -+ -+ if (volume->mount != NULL) -+ g_gdu_mount_unset_volume (volume->mount, volume); -+ -+ if (volume->drive != NULL) -+ g_gdu_drive_unset_volume (volume->drive, volume); -+ -+ if (volume->gdu_volume != NULL) -+ { -+ g_signal_handlers_disconnect_by_func (volume->gdu_volume, gdu_volume_changed, volume); -+ g_signal_handlers_disconnect_by_func (volume->gdu_volume, gdu_volume_job_changed, volume); -+ g_object_unref (volume->gdu_volume); -+ } -+ -+ if (volume->cleartext_gdu_volume != NULL) -+ { -+ g_signal_handlers_disconnect_by_func (volume->cleartext_gdu_volume, gdu_cleartext_volume_removed, volume); -+ g_signal_handlers_disconnect_by_func (volume->cleartext_gdu_volume, gdu_cleartext_volume_changed, volume); -+ g_signal_handlers_disconnect_by_func (volume->cleartext_gdu_volume, gdu_cleartext_volume_job_changed, volume); -+ g_object_unref (volume->cleartext_gdu_volume); -+ } -+ -+ if (volume->icon != NULL) -+ g_object_unref (volume->icon); -+ if (volume->activation_root != NULL) -+ g_object_unref (volume->activation_root); -+ -+ g_free (volume->name); -+ g_free (volume->device_file); -+ g_free (volume->uuid); -+ -+ if (G_OBJECT_CLASS (g_gdu_volume_parent_class)->finalize) -+ (*G_OBJECT_CLASS (g_gdu_volume_parent_class)->finalize) (object); -+} -+ -+static void -+g_gdu_volume_class_init (GGduVolumeClass *klass) -+{ -+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass); -+ -+ gobject_class->finalize = g_gdu_volume_finalize; -+} -+ -+static void -+g_gdu_volume_init (GGduVolume *gdu_volume) -+{ -+} -+ -+static void -+emit_changed (GGduVolume *volume) -+{ -+ g_signal_emit_by_name (volume, "changed"); -+ g_signal_emit_by_name (volume->volume_monitor, "volume_changed", volume); -+} -+ -+static gboolean -+update_volume (GGduVolume *volume) -+{ -+ GduDevice *device; -+ GduPool *pool; -+ time_t now; -+ gboolean changed; -+ gboolean old_can_mount; -+ gboolean old_should_automount; -+ gchar *old_name; -+ gchar *old_device_file; -+ GIcon *old_icon; -+ gboolean keep_cleartext_volume; -+ -+ /* save old values */ -+ old_can_mount = volume->can_mount; -+ old_should_automount = volume->should_automount; -+ old_name = g_strdup (volume->name); -+ old_device_file = g_strdup (volume->device_file); -+ old_icon = volume->icon != NULL ? g_object_ref (volume->icon) : NULL; -+ -+ /* ---------------------------------------------------------------------------------------------------- */ -+ -+ /* in with the new */ -+ device = gdu_presentable_get_device (GDU_PRESENTABLE (volume->gdu_volume)); -+ pool = gdu_device_get_pool (device); -+ -+ keep_cleartext_volume = FALSE; -+ if (gdu_device_is_luks (device)) -+ { -+ const gchar *holder_objpath; -+ -+ holder_objpath = gdu_device_luks_get_holder (device); -+ if (holder_objpath != NULL && g_strcmp0 (holder_objpath, "/") != 0) -+ { -+ GduDevice *cleartext_device; -+ -+ cleartext_device = gdu_pool_get_by_object_path (pool, holder_objpath); -+ if (cleartext_device != NULL) -+ { -+ GduVolume *cleartext_gdu_volume; -+ -+ cleartext_gdu_volume = GDU_VOLUME (gdu_pool_get_volume_by_device (pool, cleartext_device)); -+ if (cleartext_gdu_volume != volume->cleartext_gdu_volume) -+ { -+ if (volume->cleartext_gdu_volume != NULL) -+ { -+ g_signal_handlers_disconnect_by_func (volume->cleartext_gdu_volume, gdu_cleartext_volume_removed, volume); -+ g_signal_handlers_disconnect_by_func (volume->cleartext_gdu_volume, gdu_cleartext_volume_changed, volume); -+ g_signal_handlers_disconnect_by_func (volume->cleartext_gdu_volume, gdu_cleartext_volume_job_changed, volume); -+ g_object_unref (volume->cleartext_gdu_volume); -+ } -+ -+ volume->cleartext_gdu_volume = g_object_ref (cleartext_gdu_volume); -+ g_signal_connect (volume->cleartext_gdu_volume, "removed", G_CALLBACK (gdu_cleartext_volume_removed), volume); -+ g_signal_connect (volume->cleartext_gdu_volume, "changed", G_CALLBACK (gdu_cleartext_volume_changed), volume); -+ g_signal_connect (volume->cleartext_gdu_volume, "job-changed", G_CALLBACK (gdu_cleartext_volume_job_changed), volume); -+ } -+ g_object_unref (cleartext_gdu_volume); -+ -+ g_object_unref (cleartext_device); -+ -+ keep_cleartext_volume = TRUE; -+ } -+ } -+ } -+ -+ if (!keep_cleartext_volume) -+ { -+ if (volume->cleartext_gdu_volume != NULL) -+ { -+ g_signal_handlers_disconnect_by_func (volume->cleartext_gdu_volume, gdu_cleartext_volume_removed, volume); -+ g_signal_handlers_disconnect_by_func (volume->cleartext_gdu_volume, gdu_cleartext_volume_changed, volume); -+ g_signal_handlers_disconnect_by_func (volume->cleartext_gdu_volume, gdu_cleartext_volume_job_changed, volume); -+ g_object_unref (volume->cleartext_gdu_volume); -+ volume->cleartext_gdu_volume = NULL; -+ } -+ } -+ -+ -+ /* Use data from cleartext LUKS volume if it is unlocked */ -+ if (volume->cleartext_gdu_volume != NULL) -+ { -+ GduDevice *luks_cleartext_volume_device; -+ -+ luks_cleartext_volume_device = gdu_presentable_get_device (GDU_PRESENTABLE (volume->cleartext_gdu_volume)); -+ -+ if (volume->icon != NULL) -+ g_object_unref (volume->icon); -+ volume->icon = gdu_presentable_get_icon (GDU_PRESENTABLE (volume->cleartext_gdu_volume)); -+ -+ g_free (volume->name); -+ volume->name = gdu_presentable_get_name (GDU_PRESENTABLE (volume->cleartext_gdu_volume)); -+ -+ g_free (volume->device_file); -+ volume->device_file = g_strdup (gdu_device_get_device_file (luks_cleartext_volume_device)); -+ -+ volume->can_mount = TRUE; -+ -+ volume->should_automount = FALSE; -+ -+ g_object_unref (luks_cleartext_volume_device); -+ } -+ else -+ { -+ gchar *activation_uri; -+ -+ if (volume->icon != NULL) -+ g_object_unref (volume->icon); -+ volume->icon = gdu_presentable_get_icon (GDU_PRESENTABLE (volume->gdu_volume)); -+ -+ g_free (volume->name); -+ volume->name = gdu_presentable_get_name (GDU_PRESENTABLE (volume->gdu_volume)); -+ -+ /* special case the name and icon for audio discs */ -+ activation_uri = volume->activation_root != NULL ? g_file_get_uri (volume->activation_root) : NULL; -+ if (activation_uri != NULL && g_str_has_prefix (activation_uri, "cdda://")) -+ { -+ if (volume->icon != NULL) -+ g_object_unref (volume->icon); -+ volume->icon = g_themed_icon_new_with_default_fallbacks ("media-optical-audio"); -+ g_free (volume->name); -+ volume->name = g_strdup (_("Audio Disc")); -+ } -+ -+ g_free (volume->device_file); -+ volume->device_file = g_strdup (gdu_device_get_device_file (device)); -+ -+ volume->can_mount = TRUE; -+ -+ /* If a volume (partition) appear _much later_ than when media was insertion it -+ * can only be because the media was repartitioned. We don't want to automount -+ * such volumes. -+ */ -+ volume->should_automount = TRUE; -+ if (volume->drive != NULL) -+ { -+ now = time (NULL); -+ if (now - g_gdu_drive_get_time_of_last_media_insertion (volume->drive) > 5) -+ volume->should_automount = FALSE; -+ } -+ -+ g_free (activation_uri); -+ } -+ -+ g_object_unref (pool); -+ g_object_unref (device); -+ -+ /* ---------------------------------------------------------------------------------------------------- */ -+ -+ /* compute whether something changed */ -+ changed = !((old_can_mount == volume->can_mount) && -+ (old_should_automount == volume->should_automount) && -+ (g_strcmp0 (old_name, volume->name) == 0) && -+ (g_strcmp0 (old_device_file, volume->device_file) == 0) && -+ g_icon_equal (old_icon, volume->icon) -+ ); -+ -+ /* free old values */ -+ g_free (old_name); -+ g_free (old_device_file); -+ if (old_icon != NULL) -+ g_object_unref (old_icon); -+ -+ /*g_debug ("in update_volume(), changed=%d", changed);*/ -+ -+ return changed; -+} -+ -+static void -+gdu_volume_changed (GduPresentable *presentable, -+ GGduVolume *volume) -+{ -+ /*g_debug ("volume: presentable_changed: %p: %s", volume, gdu_presentable_get_id (GDU_PRESENTABLE (presentable)));*/ -+ if (update_volume (volume)) -+ emit_changed (volume); -+} -+ -+static void -+gdu_volume_job_changed (GduPresentable *presentable, -+ GGduVolume *volume) -+{ -+ /*g_debug ("volume: presentable_job_changed %p: %s", volume, gdu_presentable_get_id (GDU_PRESENTABLE (presentable)));*/ -+ if (update_volume (volume)) -+ emit_changed (volume); -+} -+ -+static void -+gdu_cleartext_volume_removed (GduPresentable *presentable, -+ GGduVolume *volume) -+{ -+ /*g_debug ("cleartext volume: presentable_removed: %p: %s", volume, gdu_presentable_get_id (GDU_PRESENTABLE (presentable)));*/ -+ if (update_volume (volume)) -+ emit_changed (volume); -+} -+ -+static void -+gdu_cleartext_volume_changed (GduPresentable *presentable, -+ GGduVolume *volume) -+{ -+ /*g_debug ("cleartext volume: presentable_changed: %p: %s", volume, gdu_presentable_get_id (GDU_PRESENTABLE (presentable)));*/ -+ if (update_volume (volume)) -+ emit_changed (volume); -+} -+ -+static void -+gdu_cleartext_volume_job_changed (GduPresentable *presentable, -+ GGduVolume *volume) -+{ -+ /*g_debug ("cleartext volume: presentable_job_changed %p: %s", volume, gdu_presentable_get_id (GDU_PRESENTABLE (presentable)));*/ -+ if (update_volume (volume)) -+ emit_changed (volume); -+} -+ -+GGduVolume * -+g_gdu_volume_new (GVolumeMonitor *volume_monitor, -+ GduVolume *gdu_volume, -+ GGduDrive *drive, -+ GFile *activation_root) -+{ -+ GGduVolume *volume; -+ -+ volume = g_object_new (G_TYPE_GDU_VOLUME, NULL); -+ volume->volume_monitor = volume_monitor; -+ g_object_add_weak_pointer (G_OBJECT (volume_monitor), (gpointer) &(volume->volume_monitor)); -+ -+ volume->gdu_volume = g_object_ref (gdu_volume); -+ volume->activation_root = activation_root != NULL ? g_object_ref (activation_root) : NULL; -+ -+ g_signal_connect (volume->gdu_volume, "changed", G_CALLBACK (gdu_volume_changed), volume); -+ g_signal_connect (volume->gdu_volume, "job-changed", G_CALLBACK (gdu_volume_job_changed), volume); -+ -+ volume->drive = drive; -+ if (drive != NULL) -+ g_gdu_drive_set_volume (drive, volume); -+ -+ update_volume (volume); -+ -+ return volume; -+} -+ -+void -+g_gdu_volume_removed (GGduVolume *volume) -+{ -+ if (volume->pending_mount_op != NULL) -+ cancel_pending_mount_op (volume->pending_mount_op); -+ -+ if (volume->mount != NULL) -+ { -+ g_gdu_mount_unset_volume (volume->mount, volume); -+ volume->mount = NULL; -+ } -+ -+ if (volume->drive != NULL) -+ { -+ g_gdu_drive_unset_volume (volume->drive, volume); -+ volume->drive = NULL; -+ } -+} -+ -+void -+g_gdu_volume_set_mount (GGduVolume *volume, -+ GGduMount *mount) -+{ -+ if (volume->mount != mount) -+ { -+ -+ if (volume->mount != NULL) -+ g_gdu_mount_unset_volume (volume->mount, volume); -+ -+ volume->mount = mount; -+ -+ emit_changed (volume); -+ } -+} -+ -+void -+g_gdu_volume_unset_mount (GGduVolume *volume, -+ GGduMount *mount) -+{ -+ if (volume->mount == mount) -+ { -+ volume->mount = NULL; -+ emit_changed (volume); -+ } -+} -+ -+void -+g_gdu_volume_set_drive (GGduVolume *volume, -+ GGduDrive *drive) -+{ -+ if (volume->drive != drive) -+ { -+ if (volume->drive != NULL) -+ g_gdu_drive_unset_volume (volume->drive, volume); -+ -+ volume->drive = drive; -+ -+ emit_changed (volume); -+ } -+} -+ -+void -+g_gdu_volume_unset_drive (GGduVolume *volume, -+ GGduDrive *drive) -+{ -+ if (volume->drive == drive) -+ { -+ volume->drive = NULL; -+ emit_changed (volume); -+ } -+} -+ -+static GIcon * -+g_gdu_volume_get_icon (GVolume *_volume) -+{ -+ GGduVolume *volume = G_GDU_VOLUME (_volume); -+ return volume->icon != NULL ? g_object_ref (volume->icon) : NULL; -+} -+ -+static char * -+g_gdu_volume_get_name (GVolume *_volume) -+{ -+ GGduVolume *volume = G_GDU_VOLUME (_volume); -+ return g_strdup (volume->name); -+} -+ -+static char * -+g_gdu_volume_get_uuid (GVolume *_volume) -+{ -+ GGduVolume *volume = G_GDU_VOLUME (_volume); -+ return g_strdup (volume->uuid); -+} -+ -+static gboolean -+g_gdu_volume_can_mount (GVolume *_volume) -+{ -+ GGduVolume *volume = G_GDU_VOLUME (_volume); -+ return volume->can_mount; -+} -+ -+static gboolean -+g_gdu_volume_can_eject (GVolume *_volume) -+{ -+ GGduVolume *volume = G_GDU_VOLUME (_volume); -+ gboolean can_eject; -+ -+ can_eject = FALSE; -+ if (volume->drive != NULL) -+ can_eject = g_drive_can_eject (G_DRIVE (volume->drive)); -+ -+ return can_eject; -+} -+ -+static gboolean -+g_gdu_volume_should_automount (GVolume *_volume) -+{ -+ GGduVolume *volume = G_GDU_VOLUME (_volume); -+ return volume->should_automount; -+} -+ -+static GDrive * -+g_gdu_volume_get_drive (GVolume *volume) -+{ -+ GGduVolume *gdu_volume = G_GDU_VOLUME (volume); -+ GDrive *drive; -+ -+ drive = NULL; -+ if (gdu_volume->drive != NULL) -+ drive = g_object_ref (gdu_volume->drive); -+ -+ return drive; -+} -+ -+static GMount * -+g_gdu_volume_get_mount (GVolume *volume) -+{ -+ GGduVolume *gdu_volume = G_GDU_VOLUME (volume); -+ GMount *mount; -+ -+ mount = NULL; -+ if (gdu_volume->mount != NULL) -+ mount = g_object_ref (gdu_volume->mount); -+ -+ return mount; -+} -+ -+/* ---------------------------------------------------------------------------------------------------- */ -+ -+struct MountOpData -+{ -+ GGduVolume *volume; -+ GduDevice *device_to_mount; -+ GSimpleAsyncResult *simple; -+ GCancellable *cancellable; -+ gulong cancelled_handler_id; -+ -+ GMountOperation *mount_operation; -+ gulong mount_operation_reply_handler_id; -+ -+ gboolean is_cancelled; -+}; -+ -+static void -+mount_op_data_unref (MountOpData *data) -+{ -+ g_object_unref (data->volume); -+ if (data->device_to_mount != NULL) -+ g_object_unref (data->device_to_mount); -+ g_object_unref (data->simple); -+ if (data->cancelled_handler_id != 0) -+ g_signal_handler_disconnect (data->cancellable, data->cancelled_handler_id); -+ if (data->cancellable != NULL) -+ g_object_unref (data->cancellable); -+ if (data->mount_operation_reply_handler_id != 0) -+ g_signal_handler_disconnect (data->mount_operation, data->mount_operation_reply_handler_id); -+ if (data->mount_operation != NULL) -+ g_object_unref (data->mount_operation); -+ g_free (data); -+} -+ -+static void -+cancel_pending_mount_op (MountOpData *data) -+{ -+ /* we are no longer pending */ -+ data->volume->pending_mount_op = NULL; -+ -+ data->is_cancelled = TRUE; -+ -+ /* send an ::aborted signal to make the dialog go away */ -+ if (data->mount_operation != NULL) -+ g_signal_emit_by_name (data->mount_operation, "aborted"); -+ -+ /* complete the operation (sends reply to caller) */ -+ g_simple_async_result_set_error (data->simple, -+ G_IO_ERROR, -+ G_IO_ERROR_FAILED_HANDLED, -+ "Operation was cancelled"); -+ g_simple_async_result_complete (data->simple); -+} -+ -+static void -+mount_cb (GduDevice *device, -+ gchar *mount_point, -+ GError *error, -+ gpointer user_data); -+ -+static void -+mount_obtain_authz_cb (GObject *source_object, -+ GAsyncResult *res, -+ gpointer user_data) -+{ -+ MountOpData *data = user_data; -+ gboolean obtained_authz; -+ GError *error; -+ -+ /* if we've already aborted due to device removal / cancellation, just bail out */ -+ if (data->is_cancelled) -+ goto bailout; -+ -+ error = NULL; -+ obtained_authz = _obtain_authz_finish (res, &error); -+ -+ if (!obtained_authz) -+ { -+ /* be quiet if the daemon is inhibited */ -+ if (error->code == GDU_ERROR_INHIBITED) -+ { -+ error->domain = G_IO_ERROR; -+ error->code = G_IO_ERROR_FAILED_HANDLED; -+ } -+ g_simple_async_result_set_from_error (data->simple, error); -+ g_simple_async_result_complete (data->simple); -+ } -+ else -+ { -+ /* got the authz, now try again */ -+ gdu_device_op_filesystem_mount (data->device_to_mount, mount_cb, data); -+ goto out; -+ } -+ -+ bailout: -+ data->volume->pending_mount_op = NULL; -+ mount_op_data_unref (data); -+ -+ out: -+ ; -+} -+ -+static void -+mount_cb (GduDevice *device, -+ gchar *mount_point, -+ GError *error, -+ gpointer user_data) -+{ -+ MountOpData *data = user_data; -+ -+ /* if we've already aborted due to device removal / cancellation, just bail out */ -+ if (data->is_cancelled) -+ goto bailout; -+ -+ if (error != NULL) -+ { -+ PolKitAction *pk_action; -+ PolKitResult pk_result; -+ -+ /* only attempt to show authentication dialog if we have a mount operation */ -+ if (data->mount_operation != NULL && gdu_error_check_polkit_not_authorized (error, -+ &pk_action, -+ &pk_result)) -+ { -+ if (pk_result != POLKIT_RESULT_NO && pk_result != POLKIT_RESULT_UNKNOWN) -+ { -+ const gchar *action_id; -+ /* try to obtain the authorization */ -+ polkit_action_get_action_id (pk_action, (char **) &action_id); -+ _obtain_authz (action_id, -+ data->cancellable, -+ mount_obtain_authz_cb, -+ data); -+ goto out; -+ } -+ else -+ { -+ g_simple_async_result_set_from_error (data->simple, error); -+ } -+ polkit_action_unref (pk_action); -+ } -+ else -+ { -+ /* be quiet if the daemon is inhibited */ -+ if (error->code == GDU_ERROR_INHIBITED) -+ { -+ error->domain = G_IO_ERROR; -+ error->code = G_IO_ERROR_FAILED_HANDLED; -+ } -+ g_simple_async_result_set_from_error (data->simple, error); -+ } -+ g_error_free (error); -+ } -+ else -+ { -+ g_free (mount_point); -+ } -+ -+ g_simple_async_result_complete (data->simple); -+ -+ bailout: -+ data->volume->pending_mount_op = NULL; -+ mount_op_data_unref (data); -+ -+ out: -+ ; -+} -+ -+static void -+mount_cleartext_device (MountOpData *data, -+ const gchar *object_path_of_cleartext_device) -+{ -+ GduPool *pool; -+ -+ /* if we've already aborted due to device removal / cancellation, just bail out */ -+ if (data->is_cancelled) -+ { -+ mount_op_data_unref (data); -+ goto bailout; -+ } -+ -+ pool = gdu_presentable_get_pool (GDU_PRESENTABLE (data->volume->gdu_volume)); -+ -+ data->device_to_mount = gdu_pool_get_by_object_path (pool, object_path_of_cleartext_device); -+ if (data->device_to_mount == NULL) -+ { -+ g_simple_async_result_set_error (data->simple, -+ G_IO_ERROR, -+ G_IO_ERROR_FAILED, -+ "Successfully unlocked encrypted volume but cleartext device does not exist"); -+ g_simple_async_result_complete (data->simple); -+ data->volume->pending_mount_op = NULL; -+ mount_op_data_unref (data); -+ } -+ else -+ { -+ gdu_device_op_filesystem_mount (data->device_to_mount, mount_cb, data); -+ } -+ -+ g_object_unref (pool); -+ -+ bailout: -+ ; -+} -+ -+static void -+unlock_from_keyring_cb (GduDevice *device, -+ char *object_path_of_cleartext_device, -+ GError *error, -+ gpointer user_data) -+{ -+ MountOpData *data = user_data; -+ -+ /* if we've already aborted due to device removal / cancellation, just bail out */ -+ if (data->is_cancelled) -+ { -+ mount_op_data_unref (data); -+ goto bailout; -+ } -+ -+ if (error != NULL) -+ { -+ /*g_debug ("keyring password didn't work: %s", error->message);*/ -+ -+ /* The password we retrieved from the keyring didn't work. So go ahead and prompt -+ * the user. -+ */ -+ mount_with_mount_operation (data); -+ -+ g_error_free (error); -+ } -+ else -+ { -+ mount_cleartext_device (data, object_path_of_cleartext_device); -+ g_free (object_path_of_cleartext_device); -+ } -+ -+ bailout: -+ ; -+} -+ -+static void -+unlock_cb (GduDevice *device, -+ gchar *object_path_of_cleartext_device, -+ GError *error, -+ gpointer user_data) -+{ -+ MountOpData *data = user_data; -+ -+ /* if we've already aborted due to device removal / cancellation, just bail out */ -+ if (data->is_cancelled) -+ { -+ mount_op_data_unref (data); -+ goto bailout; -+ } -+ -+ if (error != NULL) -+ { -+ /* be quiet if the daemon is inhibited */ -+ if (error->code == GDU_ERROR_INHIBITED) -+ { -+ error->domain = G_IO_ERROR; -+ error->code = G_IO_ERROR_FAILED_HANDLED; -+ } -+ g_simple_async_result_set_from_error (data->simple, error); -+ g_error_free (error); -+ g_simple_async_result_complete (data->simple); -+ data->volume->pending_mount_op = NULL; -+ mount_op_data_unref (data); -+ } -+ else -+ { -+ GPasswordSave password_save; -+ const gchar *password; -+ -+ password_save = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (device), "password-save")); -+ password = g_object_get_data (G_OBJECT (device), "password"); -+ -+ if (password != NULL) -+ { -+ switch (password_save) -+ { -+ case G_PASSWORD_SAVE_FOR_SESSION: -+ gdu_util_save_secret (device, password, TRUE); -+ break; -+ -+ case G_PASSWORD_SAVE_PERMANENTLY: -+ gdu_util_save_secret (device, password, FALSE); -+ break; -+ -+ default: -+ /* do nothing */ -+ break; -+ } -+ } -+ -+ /* now we have a cleartext device; update the GVolume details to show that */ -+ if (update_volume (data->volume)) -+ emit_changed (data->volume); -+ -+ mount_cleartext_device (data, object_path_of_cleartext_device); -+ g_free (object_path_of_cleartext_device); -+ } -+ -+ bailout: -+ -+ /* scrub the password */ -+ g_object_set_data (G_OBJECT (device), "password-save", NULL); -+ g_object_set_data (G_OBJECT (device), "password", NULL); -+} -+ -+static void -+scrub_n_free_string (char *password) -+{ -+ memset (password, '\0', strlen (password)); -+ g_free (password); -+} -+ -+static void -+mount_operation_reply (GMountOperation *mount_operation, -+ GMountOperationResult result, -+ gpointer user_data) -+{ -+ MountOpData *data = user_data; -+ GduDevice *device; -+ const gchar *password; -+ -+ /* if we've already aborted due to device removal, just bail out */ -+ if (data->is_cancelled) -+ { -+ mount_op_data_unref (data); -+ goto out; -+ } -+ -+ /* we got what we wanted; don't listen to any other signals from the mount operation */ -+ if (data->mount_operation_reply_handler_id != 0) -+ { -+ g_signal_handler_disconnect (data->mount_operation, data->mount_operation_reply_handler_id); -+ data->mount_operation_reply_handler_id = 0; -+ } -+ -+ if (result != G_MOUNT_OPERATION_HANDLED) -+ { -+ if (result == G_MOUNT_OPERATION_ABORTED) -+ { -+ /* The user aborted the operation so consider it "handled" */ -+ g_simple_async_result_set_error (data->simple, -+ G_IO_ERROR, -+ G_IO_ERROR_FAILED_HANDLED, -+ "Password dialog aborted (user should never see this error since it is G_IO_ERROR_FAILED_HANDLED)"); -+ } -+ else -+ { -+ g_simple_async_result_set_error (data->simple, -+ G_IO_ERROR, -+ G_IO_ERROR_PERMISSION_DENIED, -+ "Expected G_MOUNT_OPERATION_HANDLED but got %d", result); -+ } -+ g_simple_async_result_complete (data->simple); -+ data->volume->pending_mount_op = NULL; -+ mount_op_data_unref (data); -+ goto out; -+ } -+ -+ password = g_mount_operation_get_password (mount_operation); -+ -+ device = gdu_presentable_get_device (GDU_PRESENTABLE (data->volume->gdu_volume)); -+ -+ g_object_set_data (G_OBJECT (device), -+ "password-save", -+ GINT_TO_POINTER (g_mount_operation_get_password_save (mount_operation))); -+ g_object_set_data_full (G_OBJECT (device), -+ "password", -+ g_strdup (password), -+ (GDestroyNotify) scrub_n_free_string); -+ -+ gdu_device_op_luks_unlock (device, password, unlock_cb, data); -+ -+ g_object_unref (device); -+ -+ out: -+ ; -+} -+ -+static void -+mount_with_mount_operation (MountOpData *data) -+{ -+ gchar *message; -+ gchar *drive_name; -+ GduPresentable *toplevel; -+ GduDevice *device; -+ -+ device = NULL; -+ drive_name = NULL; -+ message = NULL; -+ toplevel = NULL; -+ -+ /* if we've already aborted due to device removal, just bail out */ -+ if (data->is_cancelled) -+ { -+ mount_op_data_unref (data); -+ goto out; -+ } -+ -+ if (data->mount_operation == NULL) -+ { -+ g_simple_async_result_set_error (data->simple, -+ G_IO_ERROR, -+ G_IO_ERROR_FAILED, -+ "Password required to access the encrypted data"); -+ g_simple_async_result_complete (data->simple); -+ data->volume->pending_mount_op = NULL; -+ mount_op_data_unref (data); -+ goto out; -+ } -+ -+ device = gdu_presentable_get_device (GDU_PRESENTABLE (data->volume->gdu_volume)); -+ -+ toplevel = gdu_presentable_get_toplevel (GDU_PRESENTABLE (data->volume->gdu_volume)); -+ if (toplevel != NULL) -+ drive_name = gdu_presentable_get_name (toplevel); -+ -+ /* This is going to look ass until bug 573416 is fixed. Unfortunately -+ * the gtk+ maintain has stated "oh, I stopped using luks" but that's -+ * more of a gtk+ problem ;-) -+ */ -+ if (drive_name != NULL) -+ { -+ if (gdu_device_is_partition (device)) -+ { -+ message = g_strdup_printf (_("Enter a password to unlock the volume\n" -+ "The device \"%s\" contains encrypted data on partition %d."), -+ drive_name, -+ gdu_device_partition_get_number (device)); -+ } -+ else -+ { -+ message = g_strdup_printf (_("Enter a password to unlock the volume\n" -+ "The device \"%s\" contains encrypted data."), -+ drive_name); -+ } -+ } -+ else -+ { -+ message = g_strdup_printf (_("Enter a password to unlock the volume\n" -+ "The device %s contains encrypted data."), -+ gdu_device_get_device_file (device)); -+ } -+ -+ data->mount_operation_reply_handler_id = g_signal_connect (data->mount_operation, -+ "reply", -+ G_CALLBACK (mount_operation_reply), -+ data); -+ -+ g_signal_emit_by_name (data->mount_operation, -+ "ask-password", -+ message, -+ NULL, -+ NULL, -+ G_ASK_PASSWORD_NEED_PASSWORD | -+ G_ASK_PASSWORD_SAVING_SUPPORTED); -+ -+ out: -+ g_free (drive_name); -+ g_free (message); -+ if (device != NULL) -+ g_object_unref (device); -+ if (toplevel != NULL) -+ g_object_unref (toplevel); -+} -+ -+static void -+cancelled_cb (GCancellable *cancellable, -+ GGduVolume *volume) -+{ -+ if (volume->pending_mount_op != NULL) -+ { -+ cancel_pending_mount_op (volume->pending_mount_op); -+ } -+} -+ -+static void -+g_gdu_volume_mount (GVolume *_volume, -+ GMountMountFlags flags, -+ GMountOperation *mount_operation, -+ GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data) -+{ -+ GGduVolume *volume = G_GDU_VOLUME (_volume); -+ GSimpleAsyncResult *simple; -+ GduDevice *device; -+ GduPool *pool; -+ const gchar *usage; -+ const gchar *type; -+ MountOpData *data; -+ -+ pool = NULL; -+ device = NULL; -+ -+ if (volume->pending_mount_op != NULL) -+ { -+ simple = g_simple_async_result_new_error (G_OBJECT (volume), -+ callback, -+ user_data, -+ G_IO_ERROR, -+ G_IO_ERROR_FAILED, -+ "A mount operation is already pending"); -+ g_simple_async_result_complete (simple); -+ g_object_unref (simple); -+ goto out; -+ } -+ -+ device = gdu_presentable_get_device (GDU_PRESENTABLE (volume->gdu_volume)); -+ pool = gdu_device_get_pool (device); -+ -+ /* Makes no sense to mount -+ * -+ * - blank discs since these already have a burn:/// mount -+ * - other things that are already mounted -+ * -+ * Unfortunately Nautilus will try to do this anyway. For now, just return success for -+ * such requests. -+ */ -+ if (gdu_device_optical_disc_get_is_blank (device) || gdu_device_is_mounted (device)) -+ { -+ simple = g_simple_async_result_new (G_OBJECT (volume), -+ callback, -+ user_data, -+ g_gdu_volume_mount); -+ g_simple_async_result_complete (simple); -+ g_object_unref (simple); -+ goto out; -+ } -+ -+ data = g_new0 (MountOpData, 1); -+ -+ data->volume = g_object_ref (volume); -+ -+ data->simple = g_simple_async_result_new (G_OBJECT (volume), -+ callback, -+ user_data, -+ g_gdu_volume_mount); -+ -+ data->cancellable = cancellable != NULL ? g_object_ref (cancellable) : NULL; -+ -+ data->mount_operation = mount_operation != NULL ? g_object_ref (mount_operation) : NULL; -+ -+ if (data->cancellable != NULL) -+ data->cancelled_handler_id = g_signal_connect (data->cancellable, "cancelled", G_CALLBACK (cancelled_cb), volume); -+ -+ volume->pending_mount_op = data; -+ -+ /* if the device is already unlocked, just attempt to mount it */ -+ if (volume->cleartext_gdu_volume != NULL) -+ { -+ GduDevice *luks_cleartext_volume_device; -+ const gchar *object_path_of_cleartext_device; -+ -+ luks_cleartext_volume_device = gdu_presentable_get_device (GDU_PRESENTABLE (volume->cleartext_gdu_volume)); -+ -+ object_path_of_cleartext_device = gdu_device_get_object_path (luks_cleartext_volume_device); -+ -+ mount_cleartext_device (data, object_path_of_cleartext_device); -+ -+ g_object_unref (luks_cleartext_volume_device); -+ goto out; -+ } -+ -+ usage = gdu_device_id_get_usage (device); -+ type = gdu_device_id_get_type (device); -+ if (g_strcmp0 (usage, "crypto") == 0 && g_strcmp0 (type, "crypto_LUKS") == 0) -+ { -+ gchar *password; -+ -+ /* if we have the secret in the keyring, try with that first */ -+ password = gdu_util_get_secret (device); -+ if (password != NULL) -+ { -+ gdu_device_op_luks_unlock (device, password, unlock_from_keyring_cb, data); -+ -+ scrub_n_free_string (password); -+ goto out; -+ } -+ -+ /* don't put up a password dialog if the daemon is inhibited */ -+ if (gdu_pool_is_daemon_inhibited (pool)) -+ { -+ g_simple_async_result_set_error (data->simple, -+ G_IO_ERROR, -+ G_IO_ERROR_FAILED_HANDLED, -+ "Daemon is currently inhibited"); -+ g_simple_async_result_complete (data->simple); -+ volume->pending_mount_op = NULL; -+ mount_op_data_unref (data); -+ goto out; -+ } -+ -+ mount_with_mount_operation (data); -+ } -+ else -+ { -+ data->device_to_mount = g_object_ref (device); -+ gdu_device_op_filesystem_mount (data->device_to_mount, mount_cb, data); -+ } -+ -+ out: -+ if (pool != NULL) -+ g_object_unref (pool); -+ if (device != NULL) -+ g_object_unref (device); -+} -+ -+static gboolean -+g_gdu_volume_mount_finish (GVolume *volume, -+ GAsyncResult *result, -+ GError **error) -+{ -+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result); -+ -+ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_gdu_volume_mount); -+ -+ return !g_simple_async_result_propagate_error (simple, error); -+} -+ -+/* ---------------------------------------------------------------------------------------------------- */ -+ -+typedef struct { -+ GObject *object; -+ GAsyncReadyCallback callback; -+ gpointer user_data; -+} EjectWrapperOp; -+ -+static void -+eject_wrapper_callback (GObject *source_object, -+ GAsyncResult *res, -+ gpointer user_data) -+{ -+ EjectWrapperOp *data = user_data; -+ data->callback (data->object, res, data->user_data); -+ g_object_unref (data->object); -+ g_free (data); -+} -+ -+static void -+g_gdu_volume_eject (GVolume *volume, -+ GMountUnmountFlags flags, -+ GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data) -+{ -+ GGduVolume *gdu_volume = G_GDU_VOLUME (volume); -+ GGduDrive *drive; -+ -+ drive = NULL; -+ if (gdu_volume->drive != NULL) -+ drive = g_object_ref (gdu_volume->drive); -+ -+ if (drive != NULL) -+ { -+ EjectWrapperOp *data; -+ data = g_new0 (EjectWrapperOp, 1); -+ data->object = g_object_ref (volume); -+ data->callback = callback; -+ data->user_data = user_data; -+ g_drive_eject (G_DRIVE (drive), flags, cancellable, eject_wrapper_callback, data); -+ g_object_unref (drive); -+ } -+ else -+ { -+ GSimpleAsyncResult *simple; -+ simple = g_simple_async_result_new_error (G_OBJECT (volume), -+ callback, -+ user_data, -+ G_IO_ERROR, -+ G_IO_ERROR_FAILED, -+ _("Operation not supported by backend")); -+ g_simple_async_result_complete (simple); -+ g_object_unref (simple); -+ } -+} -+ -+static gboolean -+g_gdu_volume_eject_finish (GVolume *volume, -+ GAsyncResult *result, -+ GError **error) -+{ -+ GGduVolume *gdu_volume = G_GDU_VOLUME (volume); -+ gboolean res; -+ -+ res = TRUE; -+ if (gdu_volume->drive != NULL) -+ { -+ res = g_drive_eject_finish (G_DRIVE (gdu_volume->drive), result, error); -+ } -+ else -+ { -+ g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error); -+ res = FALSE; -+ } -+ -+ return res; -+} -+ -+static char * -+g_gdu_volume_get_identifier (GVolume *_volume, -+ const char *kind) -+{ -+ GGduVolume *volume = G_GDU_VOLUME (_volume); -+ GduDevice *device; -+ const gchar *label; -+ const gchar *uuid; -+ gchar *id; -+ -+ id = NULL; -+ -+ device = gdu_presentable_get_device (GDU_PRESENTABLE (volume->gdu_volume)); -+ -+ label = gdu_device_id_get_label (device); -+ uuid = gdu_device_id_get_uuid (device); -+ -+ g_object_unref (device); -+ -+ if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE) == 0) -+ id = g_strdup (volume->device_file); -+ else if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_LABEL) == 0) -+ id = strlen (label) > 0 ? g_strdup (label) : NULL; -+ else if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_UUID) == 0) -+ id = strlen (uuid) > 0 ? g_strdup (uuid) : NULL; -+ -+ return id; -+} -+ -+static char ** -+g_gdu_volume_enumerate_identifiers (GVolume *_volume) -+{ -+ GGduVolume *volume = G_GDU_VOLUME (_volume); -+ GduDevice *device; -+ GPtrArray *p; -+ const gchar *label; -+ const gchar *uuid; -+ -+ device = gdu_presentable_get_device (GDU_PRESENTABLE (volume->gdu_volume)); -+ -+ label = gdu_device_id_get_label (device); -+ uuid = gdu_device_id_get_uuid (device); -+ -+ g_object_unref (device); -+ -+ p = g_ptr_array_new (); -+ g_ptr_array_add (p, g_strdup (G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE)); -+ if (strlen (label) > 0) -+ g_ptr_array_add (p, g_strdup (G_VOLUME_IDENTIFIER_KIND_LABEL)); -+ if (strlen (uuid) > 0) -+ g_ptr_array_add (p, g_strdup (G_VOLUME_IDENTIFIER_KIND_UUID)); -+ -+ g_ptr_array_add (p, NULL); -+ -+ return (gchar **) g_ptr_array_free (p, FALSE); -+} -+ -+static GFile * -+g_gdu_volume_get_activation_root (GVolume *_volume) -+{ -+ GGduVolume *volume = G_GDU_VOLUME (_volume); -+ return volume->activation_root != NULL ? g_object_ref (volume->activation_root) : NULL; -+} -+ -+static void -+g_gdu_volume_volume_iface_init (GVolumeIface *iface) -+{ -+ iface->get_name = g_gdu_volume_get_name; -+ iface->get_icon = g_gdu_volume_get_icon; -+ iface->get_uuid = g_gdu_volume_get_uuid; -+ iface->get_drive = g_gdu_volume_get_drive; -+ iface->get_mount = g_gdu_volume_get_mount; -+ iface->can_mount = g_gdu_volume_can_mount; -+ iface->can_eject = g_gdu_volume_can_eject; -+ iface->should_automount = g_gdu_volume_should_automount; -+ iface->mount_fn = g_gdu_volume_mount; -+ iface->mount_finish = g_gdu_volume_mount_finish; -+ iface->eject = g_gdu_volume_eject; -+ iface->eject_finish = g_gdu_volume_eject_finish; -+ iface->get_identifier = g_gdu_volume_get_identifier; -+ iface->enumerate_identifiers = g_gdu_volume_enumerate_identifiers; -+ iface->get_activation_root = g_gdu_volume_get_activation_root; -+} -+ -+gboolean -+g_gdu_volume_has_device_file (GGduVolume *volume, -+ const gchar *device_file) -+{ -+ const gchar *_device_file; -+ -+ _device_file = volume->device_file; -+ -+ if (volume->cleartext_gdu_volume != NULL) -+ { -+ GduDevice *luks_cleartext_volume_device; -+ luks_cleartext_volume_device = gdu_presentable_get_device (GDU_PRESENTABLE (volume->cleartext_gdu_volume)); -+ _device_file = gdu_device_get_device_file (luks_cleartext_volume_device); -+ g_object_unref (luks_cleartext_volume_device); -+ } -+ -+ return g_strcmp0 (_device_file, device_file) == 0; -+} -+ -+ -+gboolean -+g_gdu_volume_has_mount_path (GGduVolume *volume, -+ const char *mount_path) -+{ -+ GduDevice *device; -+ GduPresentable *presentable; -+ gboolean ret; -+ -+ ret = FALSE; -+ -+ presentable = g_gdu_volume_get_presentable_with_cleartext (volume); -+ if (presentable != NULL) -+ { -+ device = gdu_presentable_get_device (presentable); -+ if (device != NULL) -+ { -+ ret = g_strcmp0 (gdu_device_get_mount_path (device), mount_path) == 0; -+ g_object_unref (device); -+ } -+ } -+ -+ return ret; -+} -+ -+gboolean -+g_gdu_volume_has_uuid (GGduVolume *volume, -+ const char *uuid) -+{ -+ const gchar *_uuid; -+ -+ _uuid = volume->uuid; -+ -+ if (volume->cleartext_gdu_volume != NULL) -+ { -+ GduDevice *luks_cleartext_volume_device; -+ luks_cleartext_volume_device = gdu_presentable_get_device (GDU_PRESENTABLE (volume->cleartext_gdu_volume)); -+ _uuid = gdu_device_id_get_uuid (luks_cleartext_volume_device); -+ g_object_unref (luks_cleartext_volume_device); -+ } -+ -+ return g_strcmp0 (_uuid, uuid) == 0; -+} -+ -+GduPresentable * -+g_gdu_volume_get_presentable (GGduVolume *volume) -+{ -+ return GDU_PRESENTABLE (volume->gdu_volume); -+} -+ -+GduPresentable * -+g_gdu_volume_get_presentable_with_cleartext (GGduVolume *volume) -+{ -+ GduVolume *ret; -+ -+ ret = volume->cleartext_gdu_volume; -+ if (ret == NULL) -+ ret = volume->gdu_volume; -+ -+ return GDU_PRESENTABLE (ret); -+} -diff --git a/monitor/gdu/ggduvolume.h b/monitor/gdu/ggduvolume.h -new file mode 100644 -index 0000000..8fd7358 ---- /dev/null -+++ b/monitor/gdu/ggduvolume.h -@@ -0,0 +1,78 @@ -+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -+/* gvfs - extensions for gio -+ * -+ * Copyright (C) 2006-2009 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., 59 Temple Place, Suite 330, -+ * Boston, MA 02111-1307, USA. -+ * -+ * Author: David Zeuthen -+ */ -+ -+#ifndef __G_GDU_VOLUME_H__ -+#define __G_GDU_VOLUME_H__ -+ -+#include -+#include -+ -+#include "ggduvolumemonitor.h" -+ -+G_BEGIN_DECLS -+ -+#define G_TYPE_GDU_VOLUME (g_gdu_volume_get_type ()) -+#define G_GDU_VOLUME(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_GDU_VOLUME, GGduVolume)) -+#define G_GDU_VOLUME_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_GDU_VOLUME, GGduVolumeClass)) -+#define G_IS_GDU_VOLUME(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_GDU_VOLUME)) -+#define G_IS_GDU_VOLUME_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_GDU_VOLUME)) -+ -+typedef struct _GGduVolumeClass GGduVolumeClass; -+ -+struct _GGduVolumeClass { -+ GObjectClass parent_class; -+}; -+ -+GType g_gdu_volume_get_type (void) G_GNUC_CONST; -+ -+GGduVolume *g_gdu_volume_new (GVolumeMonitor *volume_monitor, -+ GduVolume *gdu_volume, -+ GGduDrive *drive, -+ GFile *activation_root); -+ -+void g_gdu_volume_set_mount (GGduVolume *volume, -+ GGduMount *mount); -+void g_gdu_volume_unset_mount (GGduVolume *volume, -+ GGduMount *mount); -+ -+void g_gdu_volume_set_drive (GGduVolume *volume, -+ GGduDrive *drive); -+void g_gdu_volume_unset_drive (GGduVolume *volume, -+ GGduDrive *drive); -+ -+void g_gdu_volume_removed (GGduVolume *volume); -+ -+gboolean g_gdu_volume_has_mount_path (GGduVolume *volume, -+ const char *mount_path); -+gboolean g_gdu_volume_has_uuid (GGduVolume *volume, -+ const char *uuid); -+gboolean g_gdu_volume_has_device_file (GGduVolume *volume, -+ const gchar *device_file); -+ -+GduPresentable *g_gdu_volume_get_presentable (GGduVolume *volume); -+ -+GduPresentable *g_gdu_volume_get_presentable_with_cleartext (GGduVolume *volume); -+ -+G_END_DECLS -+ -+#endif /* __G_GDU_VOLUME_H__ */ -diff --git a/monitor/gdu/ggduvolumemonitor.c b/monitor/gdu/ggduvolumemonitor.c -new file mode 100644 -index 0000000..32604d0 ---- /dev/null -+++ b/monitor/gdu/ggduvolumemonitor.c -@@ -0,0 +1,1432 @@ -+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -+/* gvfs - extensions for gio -+ * -+ * Copyright (C) 2006-2009 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., 59 Temple Place, Suite 330, -+ * Boston, MA 02111-1307, USA. -+ * -+ * Author: David Zeuthen -+ */ -+ -+#include -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "ggduvolumemonitor.h" -+#include "ggdumount.h" -+#include "ggduvolume.h" -+#include "ggdudrive.h" -+ -+static GGduVolumeMonitor *the_volume_monitor = NULL; -+ -+struct _GGduVolumeMonitor { -+ GNativeVolumeMonitor parent; -+ -+ GUnixMountMonitor *mount_monitor; -+ -+ GduPool *pool; -+ -+ GList *last_optical_disc_devices; -+ GList *last_mountpoints; -+ GList *last_mounts; -+ -+ GList *drives; -+ GList *volumes; -+ GList *mounts; -+ -+ /* we keep volumes/mounts for blank and audio discs separate to handle e.g. mixed discs properly */ -+ GList *disc_volumes; -+ GList *disc_mounts; -+ -+}; -+ -+static void mountpoints_changed (GUnixMountMonitor *mount_monitor, -+ gpointer user_data); -+static void mounts_changed (GUnixMountMonitor *mount_monitor, -+ gpointer user_data); -+ -+static void presentable_added (GduPool *pool, -+ GduPresentable *presentable, -+ gpointer user_data); -+static void presentable_removed (GduPool *pool, -+ GduPresentable *presentable, -+ gpointer user_data); -+ -+static void update_all (GGduVolumeMonitor *monitor, -+ gboolean emit_changes); -+ -+static void update_drives (GGduVolumeMonitor *monitor, -+ GList **added_drives, -+ GList **removed_drives); -+static void update_volumes (GGduVolumeMonitor *monitor, -+ GList **added_volumes, -+ GList **removed_volumes); -+static void update_mounts (GGduVolumeMonitor *monitor, -+ GList **added_mounts, -+ GList **removed_mounts); -+static void update_discs (GGduVolumeMonitor *monitor, -+ GList **added_volumes, -+ GList **removed_volumes, -+ GList **added_mounts, -+ GList **removed_mounts); -+ -+ -+G_DEFINE_TYPE (GGduVolumeMonitor, g_gdu_volume_monitor, G_TYPE_NATIVE_VOLUME_MONITOR) -+ -+static void -+list_free (GList *objects) -+{ -+ g_list_foreach (objects, (GFunc)g_object_unref, NULL); -+ g_list_free (objects); -+} -+ -+static void -+g_gdu_volume_monitor_dispose (GObject *object) -+{ -+ GGduVolumeMonitor *monitor; -+ -+ monitor = G_GDU_VOLUME_MONITOR (object); -+ -+ the_volume_monitor = NULL; -+ -+ if (G_OBJECT_CLASS (g_gdu_volume_monitor_parent_class)->dispose) -+ (*G_OBJECT_CLASS (g_gdu_volume_monitor_parent_class)->dispose) (object); -+} -+ -+static void -+g_gdu_volume_monitor_finalize (GObject *object) -+{ -+ GGduVolumeMonitor *monitor; -+ -+ monitor = G_GDU_VOLUME_MONITOR (object); -+ -+ g_signal_handlers_disconnect_by_func (monitor->mount_monitor, mountpoints_changed, monitor); -+ g_signal_handlers_disconnect_by_func (monitor->mount_monitor, mounts_changed, monitor); -+ g_signal_handlers_disconnect_by_func (monitor->mount_monitor, presentable_added, monitor); -+ g_signal_handlers_disconnect_by_func (monitor->mount_monitor, presentable_removed, monitor); -+ -+ g_object_unref (monitor->mount_monitor); -+ -+ g_object_unref (monitor->pool); -+ -+ list_free (monitor->last_optical_disc_devices); -+ list_free (monitor->last_mountpoints); -+ g_list_foreach (monitor->last_mounts, -+ (GFunc)g_unix_mount_free, NULL); -+ g_list_free (monitor->last_mounts); -+ -+ list_free (monitor->drives); -+ list_free (monitor->volumes); -+ list_free (monitor->mounts); -+ -+ list_free (monitor->disc_volumes); -+ list_free (monitor->disc_mounts); -+ -+ if (G_OBJECT_CLASS (g_gdu_volume_monitor_parent_class)->finalize) -+ (*G_OBJECT_CLASS (g_gdu_volume_monitor_parent_class)->finalize) (object); -+} -+ -+static GList * -+get_mounts (GVolumeMonitor *volume_monitor) -+{ -+ GGduVolumeMonitor *monitor; -+ GList *l, *ll; -+ -+ monitor = G_GDU_VOLUME_MONITOR (volume_monitor); -+ -+ l = g_list_copy (monitor->mounts); -+ ll = g_list_copy (monitor->disc_mounts); -+ l = g_list_concat (l, ll); -+ -+ g_list_foreach (l, (GFunc)g_object_ref, NULL); -+ -+ return l; -+} -+ -+static GList * -+get_volumes (GVolumeMonitor *volume_monitor) -+{ -+ GGduVolumeMonitor *monitor; -+ GList *l, *ll; -+ -+ monitor = G_GDU_VOLUME_MONITOR (volume_monitor); -+ -+ l = g_list_copy (monitor->volumes); -+ ll = g_list_copy (monitor->disc_volumes); -+ l = g_list_concat (l, ll); -+ -+ g_list_foreach (l, (GFunc)g_object_ref, NULL); -+ -+ return l; -+} -+ -+static GList * -+get_connected_drives (GVolumeMonitor *volume_monitor) -+{ -+ GGduVolumeMonitor *monitor; -+ GList *l; -+ -+ monitor = G_GDU_VOLUME_MONITOR (volume_monitor); -+ -+ l = g_list_copy (monitor->drives); -+ g_list_foreach (l, (GFunc)g_object_ref, NULL); -+ -+ return l; -+} -+ -+static GVolume * -+get_volume_for_uuid (GVolumeMonitor *volume_monitor, const char *uuid) -+{ -+ GGduVolumeMonitor *monitor; -+ GGduVolume *volume; -+ GList *l; -+ -+ monitor = G_GDU_VOLUME_MONITOR (volume_monitor); -+ -+ volume = NULL; -+ -+ for (l = monitor->volumes; l != NULL; l = l->next) -+ { -+ volume = l->data; -+ if (g_gdu_volume_has_uuid (volume, uuid)) -+ goto found; -+ } -+ -+ for (l = monitor->disc_volumes; l != NULL; l = l->next) -+ { -+ volume = l->data; -+ if (g_gdu_volume_has_uuid (volume, uuid)) -+ goto found; -+ } -+ -+ return NULL; -+ -+ found: -+ -+ g_object_ref (volume); -+ -+ return (GVolume *)volume; -+} -+ -+static GMount * -+get_mount_for_uuid (GVolumeMonitor *volume_monitor, const char *uuid) -+{ -+ GGduVolumeMonitor *monitor; -+ GGduMount *mount; -+ GList *l; -+ -+ monitor = G_GDU_VOLUME_MONITOR (volume_monitor); -+ -+ mount = NULL; -+ -+ for (l = monitor->mounts; l != NULL; l = l->next) -+ { -+ mount = l->data; -+ if (g_gdu_mount_has_uuid (mount, uuid)) -+ goto found; -+ } -+ -+ for (l = monitor->disc_mounts; l != NULL; l = l->next) -+ { -+ mount = l->data; -+ if (g_gdu_mount_has_uuid (mount, uuid)) -+ goto found; -+ } -+ -+ return NULL; -+ -+ found: -+ -+ g_object_ref (mount); -+ -+ return (GMount *)mount; -+} -+ -+static GMount * -+get_mount_for_mount_path (const char *mount_path, -+ GCancellable *cancellable) -+{ -+ GMount *mount; -+ GGduMount *gdu_mount; -+ GGduVolumeMonitor *volume_monitor; -+ -+ if (the_volume_monitor == NULL) -+ { -+ /* Dammit, no monitor is set up.. so we have to create one, find -+ * what the user asks for and throw it away again. -+ * -+ * What a waste - especially considering that there's IO -+ * involved in doing this: connect to the system message bus; -+ * IPC to DeviceKit-disks etc etc -+ */ -+ volume_monitor = G_GDU_VOLUME_MONITOR (g_gdu_volume_monitor_new ()); -+ } -+ else -+ { -+ volume_monitor = g_object_ref (the_volume_monitor); -+ } -+ -+ mount = NULL; -+ -+ /* creation of the volume monitor might actually fail */ -+ if (volume_monitor != NULL) -+ { -+ GList *l; -+ -+ for (l = volume_monitor->mounts; l != NULL; l = l->next) -+ { -+ gdu_mount = l->data; -+ -+ if (g_gdu_mount_has_mount_path (gdu_mount, mount_path)) -+ { -+ mount = g_object_ref (gdu_mount); -+ break; -+ } -+ } -+ } -+ -+ g_object_unref (volume_monitor); -+ -+ return (GMount *) mount; -+} -+ -+static void -+mountpoints_changed (GUnixMountMonitor *mount_monitor, -+ gpointer user_data) -+{ -+ GGduVolumeMonitor *monitor = G_GDU_VOLUME_MONITOR (user_data); -+ -+ update_all (monitor, TRUE); -+} -+ -+static void -+mounts_changed (GUnixMountMonitor *mount_monitor, -+ gpointer user_data) -+{ -+ GGduVolumeMonitor *monitor = G_GDU_VOLUME_MONITOR (user_data); -+ -+ update_all (monitor, TRUE); -+} -+ -+static void -+presentable_added (GduPool *pool, -+ GduPresentable *presentable, -+ gpointer user_data) -+{ -+ GGduVolumeMonitor *monitor = G_GDU_VOLUME_MONITOR (user_data); -+ -+ /*g_debug ("presentable_added %p: %s", presentable, gdu_presentable_get_id (presentable));*/ -+ -+ update_all (monitor, TRUE); -+} -+ -+static void -+presentable_removed (GduPool *pool, -+ GduPresentable *presentable, -+ gpointer user_data) -+{ -+ GGduVolumeMonitor *monitor = G_GDU_VOLUME_MONITOR (user_data); -+ -+ /*g_debug ("presentable_removed %p: %s", presentable, gdu_presentable_get_id (presentable));*/ -+ -+ update_all (monitor, TRUE); -+} -+ -+static void -+presentable_changed (GduPool *pool, -+ GduPresentable *presentable, -+ gpointer user_data) -+{ -+ GGduVolumeMonitor *monitor = G_GDU_VOLUME_MONITOR (user_data); -+ -+ /*g_debug ("presentable_changed %p: %s", presentable, gdu_presentable_get_id (presentable));*/ -+ -+ update_all (monitor, TRUE); -+} -+ -+static void -+presentable_job_changed (GduPool *pool, -+ GduPresentable *presentable, -+ gpointer user_data) -+{ -+ GGduVolumeMonitor *monitor = G_GDU_VOLUME_MONITOR (user_data); -+ -+ /*g_debug ("presentable_job_changed %p: %s", presentable, gdu_presentable_get_id (presentable));*/ -+ -+ update_all (monitor, TRUE); -+} -+ -+static GObject * -+g_gdu_volume_monitor_constructor (GType type, -+ guint n_construct_properties, -+ GObjectConstructParam *construct_properties) -+{ -+ GObject *object; -+ GGduVolumeMonitor *monitor; -+ GGduVolumeMonitorClass *klass; -+ GObjectClass *parent_class; -+ -+ if (the_volume_monitor != NULL) -+ { -+ object = g_object_ref (the_volume_monitor); -+ return object; -+ } -+ -+ /*g_warning ("creating gdu vm");*/ -+ -+ object = NULL; -+ -+ /* Invoke parent constructor. */ -+ klass = G_GDU_VOLUME_MONITOR_CLASS (g_type_class_peek (G_TYPE_GDU_VOLUME_MONITOR)); -+ parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass)); -+ object = parent_class->constructor (type, -+ n_construct_properties, -+ construct_properties); -+ -+ monitor = G_GDU_VOLUME_MONITOR (object); -+ -+ monitor->mount_monitor = g_unix_mount_monitor_new (); -+ -+ g_signal_connect (monitor->mount_monitor, -+ "mounts_changed", -+ G_CALLBACK (mounts_changed), -+ monitor); -+ -+ g_signal_connect (monitor->mount_monitor, -+ "mountpoints_changed", -+ G_CALLBACK (mountpoints_changed), -+ monitor); -+ -+ monitor->pool = gdu_pool_new (); -+ -+ g_signal_connect (monitor->pool, -+ "presentable_added", -+ G_CALLBACK (presentable_added), -+ monitor); -+ -+ g_signal_connect (monitor->pool, -+ "presentable_removed", -+ G_CALLBACK (presentable_removed), -+ monitor); -+ -+ g_signal_connect (monitor->pool, -+ "presentable_changed", -+ G_CALLBACK (presentable_changed), -+ monitor); -+ -+ g_signal_connect (monitor->pool, -+ "presentable_job_changed", -+ G_CALLBACK (presentable_job_changed), -+ monitor); -+ -+ update_all (monitor, FALSE); -+ -+ the_volume_monitor = monitor; -+ -+ return object; -+} -+ -+static void -+g_gdu_volume_monitor_init (GGduVolumeMonitor *monitor) -+{ -+} -+ -+static gboolean -+is_supported (void) -+{ -+ /* TODO: return FALSE if DeviceKit-disks is not available */ -+ return TRUE; -+} -+ -+static void -+g_gdu_volume_monitor_class_init (GGduVolumeMonitorClass *klass) -+{ -+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass); -+ GVolumeMonitorClass *monitor_class = G_VOLUME_MONITOR_CLASS (klass); -+ GNativeVolumeMonitorClass *native_class = G_NATIVE_VOLUME_MONITOR_CLASS (klass); -+ -+ gobject_class->constructor = g_gdu_volume_monitor_constructor; -+ gobject_class->finalize = g_gdu_volume_monitor_finalize; -+ gobject_class->dispose = g_gdu_volume_monitor_dispose; -+ -+ monitor_class->get_mounts = get_mounts; -+ monitor_class->get_volumes = get_volumes; -+ monitor_class->get_connected_drives = get_connected_drives; -+ monitor_class->get_volume_for_uuid = get_volume_for_uuid; -+ monitor_class->get_mount_for_uuid = get_mount_for_uuid; -+ monitor_class->is_supported = is_supported; -+ -+ native_class->get_mount_for_mount_path = get_mount_for_mount_path; -+} -+ -+/** -+ * g_gdu_volume_monitor_new: -+ * -+ * Returns: a new #GVolumeMonitor. -+ **/ -+GVolumeMonitor * -+g_gdu_volume_monitor_new (void) -+{ -+ GGduVolumeMonitor *monitor; -+ -+ monitor = g_object_new (G_TYPE_GDU_VOLUME_MONITOR, NULL); -+ -+ return G_VOLUME_MONITOR (monitor); -+} -+ -+static void -+diff_sorted_lists (GList *list1, -+ GList *list2, -+ GCompareFunc compare, -+ GList **added, -+ GList **removed) -+{ -+ int order; -+ -+ *added = *removed = NULL; -+ -+ while (list1 != NULL && -+ list2 != NULL) -+ { -+ order = (*compare) (list1->data, list2->data); -+ if (order < 0) -+ { -+ *removed = g_list_prepend (*removed, list1->data); -+ list1 = list1->next; -+ } -+ else if (order > 0) -+ { -+ *added = g_list_prepend (*added, list2->data); -+ list2 = list2->next; -+ } -+ else -+ { /* same item */ -+ list1 = list1->next; -+ list2 = list2->next; -+ } -+ } -+ -+ while (list1 != NULL) -+ { -+ *removed = g_list_prepend (*removed, list1->data); -+ list1 = list1->next; -+ } -+ while (list2 != NULL) -+ { -+ *added = g_list_prepend (*added, list2->data); -+ list2 = list2->next; -+ } -+} -+ -+static GGduVolume * -+find_volume_for_mount_path (GGduVolumeMonitor *monitor, -+ const char *mount_path) -+{ -+ GList *l; -+ GGduVolume *found; -+ -+ found = NULL; -+ -+ for (l = monitor->volumes; l != NULL; l = l->next) -+ { -+ GGduVolume *volume = l->data; -+ -+ if (g_gdu_volume_has_mount_path (volume, mount_path)) -+ { -+ found = volume; -+ break; -+ } -+ } -+ -+ return found; -+} -+ -+static GGduMount * -+find_mount_by_mount_path (GGduVolumeMonitor *monitor, -+ const char *mount_path) -+{ -+ GList *l; -+ -+ for (l = monitor->mounts; l != NULL; l = l->next) -+ { -+ GGduMount *mount = l->data; -+ -+ if (g_gdu_mount_has_mount_path (mount, mount_path)) -+ return mount; -+ } -+ -+ return NULL; -+} -+ -+/* TODO: move to gio */ -+static gboolean -+_g_unix_mount_point_guess_should_display (GUnixMountPoint *mount_point) -+{ -+ const char *mount_path; -+ -+ mount_path = g_unix_mount_point_get_mount_path (mount_point); -+ -+ /* Never display internal mountpoints */ -+ if (g_unix_is_mount_path_system_internal (mount_path)) -+ return FALSE; -+ -+ /* Only display things in /media (which are generally user mountable) -+ and home dir (fuse stuff) */ -+ if (g_str_has_prefix (mount_path, "/media/")) -+ return TRUE; -+ -+ if (g_str_has_prefix (mount_path, g_get_home_dir ())) -+ return TRUE; -+ -+ return FALSE; -+} -+ -+static GUnixMountPoint * -+get_mount_point_for_device (GduDevice *d, GList *fstab_mount_points) -+{ -+ GList *l; -+ const gchar *device_file; -+ const gchar *mount_path; -+ GUnixMountPoint *ret; -+ -+ ret = NULL; -+ -+ mount_path = gdu_device_get_mount_path (d); -+ -+ device_file = gdu_device_get_device_file (d); -+ -+ for (l = fstab_mount_points; l != NULL; l = l->next) -+ { -+ GUnixMountPoint *mount_point = l->data; -+ const gchar *device_file; -+ const gchar *fstab_mount_path; -+ -+ fstab_mount_path = g_unix_mount_point_get_mount_path (mount_point); -+ if (g_strcmp0 (mount_path, fstab_mount_path) == 0) -+ { -+ ret = mount_point; -+ goto out; -+ } -+ -+ device_file = g_unix_mount_point_get_device_path (mount_point); -+ if (g_str_has_prefix (device_file, "LABEL=")) -+ { -+ if (g_strcmp0 (device_file + 6, gdu_device_id_get_label (d)) == 0) -+ { -+ ret = mount_point; -+ goto out; -+ } -+ } -+ else if (g_str_has_prefix (device_file, "UUID=")) -+ { -+ if (g_ascii_strcasecmp (device_file + 5, gdu_device_id_get_uuid (d)) == 0) -+ { -+ ret = mount_point; -+ goto out; -+ } -+ } -+ else -+ { -+ char resolved_device_file[PATH_MAX]; -+ -+ /* handle symlinks such as /dev/disk/by-uuid/47C2-1994 */ -+ if (realpath (device_file, resolved_device_file) != NULL && -+ g_strcmp0 (resolved_device_file, device_file) == 0) -+ { -+ ret = mount_point; -+ goto out; -+ } -+ } -+ } -+ -+ out: -+ return ret; -+} -+ -+static gboolean -+should_mount_be_ignored (GduPool *pool, GduDevice *d) -+{ -+ gboolean ret; -+ const gchar *mount_path; -+ GUnixMountEntry *mount_entry; -+ -+ ret = FALSE; -+ -+ if (gdu_device_is_mounted (d)) -+ goto out; -+ -+ mount_path = gdu_device_get_mount_path (d); -+ if (mount_path == NULL || strlen (mount_path) == 0) -+ goto out; -+ -+ mount_entry = g_unix_mount_at (mount_path, NULL); -+ if (mount_entry != NULL) -+ { -+ if (!g_unix_mount_guess_should_display (mount_entry)) -+ { -+ ret = TRUE; -+ } -+ g_unix_mount_free (mount_entry); -+ } -+ -+ out: -+ return ret; -+} -+ -+static gboolean -+should_volume_be_ignored (GduPool *pool, GduVolume *volume, GList *fstab_mount_points) -+{ -+ GduDevice *device; -+ gboolean ret; -+ const gchar *usage; -+ const gchar *type; -+ -+ ret = TRUE; -+ device = NULL; -+ -+ device = gdu_presentable_get_device (GDU_PRESENTABLE (volume)); -+ -+ usage = gdu_device_id_get_usage (device); -+ type = gdu_device_id_get_type (device); -+ -+ if (g_strcmp0 (usage, "filesystem") == 0) -+ { -+ GUnixMountPoint *mount_point; -+ -+ /* don't ignore volumes with a mountable filesystem unless -+ * -+ * - volume is referenced in /etc/fstab and deemed to be ignored -+ * -+ * - volume is mounted and should_mount_be_ignored() deems it should be ignored -+ * -+ * - volume is a cleartext LUKS device as the cryptotext LUKS volume will morph -+ * into the cleartext volume when unlocked (see ggduvolume.c) -+ */ -+ -+ if (gdu_device_is_luks_cleartext (device)) -+ goto out; -+ -+ mount_point = get_mount_point_for_device (device, fstab_mount_points); -+ if (mount_point != NULL && !_g_unix_mount_point_guess_should_display (mount_point)) -+ goto out; -+ -+ if (gdu_device_is_mounted (device)) -+ { -+ ret = should_mount_be_ignored (pool, device); -+ goto out; -+ } -+ -+ ret = FALSE; -+ -+ } -+ else if (g_strcmp0 (usage, "crypto") == 0 && g_strcmp0 (type, "crypto_LUKS") == 0) -+ { -+ /* don't ignore LUKS volumes */ -+ ret = FALSE; -+ } -+ -+ out: -+ -+ g_object_unref (device); -+ return ret; -+} -+ -+static gboolean -+should_drive_be_ignored (GduPool *pool, GduDrive *d, GList *fstab_mount_points) -+{ -+ GduDevice *device; -+ gboolean ret; -+ gboolean has_volumes; -+ gboolean all_volumes_are_ignored; -+ GList *enclosed; -+ GList *l; -+ -+ ret = FALSE; -+ device = NULL; -+ enclosed = NULL; -+ -+ device = gdu_presentable_get_device (GDU_PRESENTABLE (d)); -+ -+ /* the GduDevice for an activatable drive (such as RAID) is NULL if the drive is not -+ * activated; never ignore these -+ */ -+ if (device == NULL) -+ goto out; -+ -+ /* never ignore drives with removable media */ -+ if (gdu_device_is_removable (device)) -+ goto out; -+ -+ has_volumes = FALSE; -+ all_volumes_are_ignored = TRUE; -+ -+ /* never ignore a drive if it has volumes that we don't want to ignore */ -+ enclosed = gdu_pool_get_enclosed_presentables (pool, GDU_PRESENTABLE (d)); -+ for (l = enclosed; l != NULL; l = l->next) -+ { -+ GduPresentable *enclosed_presentable = GDU_PRESENTABLE (l->data); -+ -+ /* There might be other presentables that GduVolume objects; for example GduVolumeHole */ -+ if (GDU_IS_VOLUME (enclosed_presentable)) -+ { -+ GduVolume *volume = GDU_VOLUME (enclosed_presentable); -+ -+ has_volumes = TRUE; -+ -+ if (!should_volume_be_ignored (pool, volume, fstab_mount_points)) -+ { -+ all_volumes_are_ignored = FALSE; -+ break; -+ } -+ } -+ } -+ -+ ret = has_volumes && all_volumes_are_ignored; -+ -+ out: -+ g_list_foreach (enclosed, (GFunc) g_object_unref, NULL); -+ g_list_free (enclosed); -+ -+ if (device != NULL) -+ g_object_unref (device); -+ -+ return ret; -+} -+ -+static void -+list_emit (GGduVolumeMonitor *monitor, -+ const char *monitor_signal, -+ const char *object_signal, -+ GList *objects) -+{ -+ GList *l; -+ -+ for (l = objects; l != NULL; l = l->next) -+ { -+ g_signal_emit_by_name (monitor, monitor_signal, l->data); -+ if (object_signal) -+ g_signal_emit_by_name (l->data, object_signal); -+ } -+} -+ -+static void -+update_all (GGduVolumeMonitor *monitor, -+ gboolean emit_changes) -+{ -+ GList *added_drives, *removed_drives; -+ GList *added_volumes, *removed_volumes; -+ GList *added_mounts, *removed_mounts; -+ -+ added_drives = NULL; -+ removed_drives = NULL; -+ added_volumes = NULL; -+ removed_volumes = NULL; -+ added_mounts = NULL; -+ removed_mounts = NULL; -+ -+ update_drives (monitor, &added_drives, &removed_drives); -+ update_volumes (monitor, &added_volumes, &removed_volumes); -+ update_mounts (monitor, &added_mounts, &removed_mounts); -+ update_discs (monitor, -+ &added_volumes, &removed_volumes, -+ &added_mounts, &removed_mounts); -+ -+ if (emit_changes) -+ { -+ list_emit (monitor, -+ "drive_disconnected", NULL, -+ removed_drives); -+ list_emit (monitor, -+ "drive_connected", NULL, -+ added_drives); -+ -+ list_emit (monitor, -+ "volume_removed", "removed", -+ removed_volumes); -+ list_emit (monitor, -+ "volume_added", NULL, -+ added_volumes); -+ -+ list_emit (monitor, -+ "mount_removed", "unmounted", -+ removed_mounts); -+ list_emit (monitor, -+ "mount_added", NULL, -+ added_mounts); -+ } -+ -+ list_free (removed_drives); -+ list_free (added_drives); -+ list_free (removed_volumes); -+ list_free (added_volumes); -+ list_free (removed_mounts); -+ list_free (added_mounts); -+} -+ -+static GGduMount * -+find_disc_mount_for_volume (GGduVolumeMonitor *monitor, -+ GGduVolume *volume) -+{ -+ GList *l; -+ -+ for (l = monitor->disc_mounts; l != NULL; l = l->next) -+ { -+ GGduMount *mount = G_GDU_MOUNT (l->data); -+ -+ if (g_gdu_mount_has_volume (mount, volume)) -+ return mount; -+ } -+ -+ return NULL; -+} -+ -+static GGduVolume * -+find_disc_volume_for_device_file (GGduVolumeMonitor *monitor, -+ const gchar *device_file) -+{ -+ GList *l; -+ -+ for (l = monitor->disc_volumes; l != NULL; l = l->next) -+ { -+ GGduVolume *volume = G_GDU_VOLUME (l->data); -+ -+ if (g_gdu_volume_has_device_file (volume, device_file)) -+ return volume; -+ } -+ -+ return NULL; -+} -+ -+static GGduVolume * -+find_volume_for_device_file (GGduVolumeMonitor *monitor, -+ const gchar *device_file) -+{ -+ GList *l; -+ -+ for (l = monitor->volumes; l != NULL; l = l->next) -+ { -+ GGduVolume *volume = G_GDU_VOLUME (l->data); -+ -+ if (g_gdu_volume_has_device_file (volume, device_file)) -+ return volume; -+ } -+ -+ return NULL; -+} -+ -+static GGduDrive * -+find_drive_by_device_file (GGduVolumeMonitor *monitor, -+ const gchar *device_file) -+{ -+ GList *l; -+ -+ for (l = monitor->drives; l != NULL; l = l->next) -+ { -+ GGduDrive *drive = G_GDU_DRIVE (l->data); -+ -+ if (g_gdu_drive_has_device_file (drive, device_file)) -+ return drive; -+ } -+ -+ return NULL; -+} -+ -+static GGduDrive * -+find_drive_by_presentable (GGduVolumeMonitor *monitor, -+ GduPresentable *presentable) -+{ -+ GList *l; -+ -+ for (l = monitor->drives; l != NULL; l = l->next) -+ { -+ GGduDrive *drive = G_GDU_DRIVE (l->data); -+ -+ if (g_gdu_drive_has_presentable (drive, presentable)) -+ return drive; -+ } -+ -+ return NULL; -+} -+ -+static void -+update_drives (GGduVolumeMonitor *monitor, -+ GList **added_drives, -+ GList **removed_drives) -+{ -+ GList *cur_drives; -+ GList *new_drives; -+ GList *removed, *added; -+ GList *l, *ll; -+ GGduDrive *drive; -+ GList *fstab_mount_points; -+ -+ fstab_mount_points = g_unix_mount_points_get (NULL); -+ -+ cur_drives = NULL; -+ for (l = monitor->drives; l != NULL; l = l->next) -+ cur_drives = g_list_prepend (cur_drives, g_gdu_drive_get_presentable (G_GDU_DRIVE (l->data))); -+ -+ /* remove devices we want to ignore - we do it here so we get to reevaluate -+ * on the next update whether they should still be ignored -+ */ -+ new_drives = gdu_pool_get_presentables (monitor->pool); -+ for (l = new_drives; l != NULL; l = ll) -+ { -+ GduPresentable *p = GDU_PRESENTABLE (l->data); -+ ll = l->next; -+ if (!GDU_IS_DRIVE (p) || should_drive_be_ignored (monitor->pool, GDU_DRIVE (p), fstab_mount_points)) -+ { -+ g_object_unref (p); -+ new_drives = g_list_delete_link (new_drives, l); -+ } -+ } -+ -+ cur_drives = g_list_sort (cur_drives, (GCompareFunc) gdu_presentable_compare); -+ new_drives = g_list_sort (new_drives, (GCompareFunc) gdu_presentable_compare); -+ diff_sorted_lists (cur_drives, -+ new_drives, (GCompareFunc) gdu_presentable_compare, -+ &added, &removed); -+ -+ for (l = removed; l != NULL; l = l->next) -+ { -+ GduPresentable *p = GDU_PRESENTABLE (l->data); -+ GduDevice *d; -+ -+ d = gdu_presentable_get_device (p); -+ -+ drive = find_drive_by_presentable (monitor, p); -+ if (drive != NULL) -+ { -+ /*g_debug ("removing drive %s", gdu_presentable_get_id (p));*/ -+ g_gdu_drive_disconnected (drive); -+ monitor->drives = g_list_remove (monitor->drives, drive); -+ *removed_drives = g_list_prepend (*removed_drives, drive); -+ } -+ if (d != NULL) -+ g_object_unref (d); -+ } -+ -+ for (l = added; l != NULL; l = l->next) -+ { -+ GduPresentable *p = GDU_PRESENTABLE (l->data); -+ GduDevice *d; -+ -+ d = gdu_presentable_get_device (p); -+ -+ drive = find_drive_by_presentable (monitor, p); -+ if (drive == NULL) -+ { -+ /*g_debug ("adding drive %s", gdu_presentable_get_id (p));*/ -+ drive = g_gdu_drive_new (G_VOLUME_MONITOR (monitor), p); -+ if (drive != NULL) -+ { -+ monitor->drives = g_list_prepend (monitor->drives, drive); -+ *added_drives = g_list_prepend (*added_drives, g_object_ref (drive)); -+ } -+ } -+ if (d != NULL) -+ g_object_unref (d); -+ } -+ -+ g_list_free (added); -+ g_list_free (removed); -+ -+ g_list_free (cur_drives); -+ -+ g_list_foreach (new_drives, (GFunc) g_object_unref, NULL); -+ g_list_free (new_drives); -+ -+ g_list_foreach (fstab_mount_points, (GFunc) g_unix_mount_point_free, NULL); -+ g_list_free (fstab_mount_points); -+} -+ -+static void -+update_volumes (GGduVolumeMonitor *monitor, -+ GList **added_volumes, -+ GList **removed_volumes) -+{ -+ GList *cur_volumes; -+ GList *new_volumes; -+ GList *removed, *added; -+ GList *l, *ll; -+ GGduVolume *volume; -+ GGduDrive *drive; -+ GList *fstab_mount_points; -+ -+ fstab_mount_points = g_unix_mount_points_get (NULL); -+ -+ cur_volumes = NULL; -+ for (l = monitor->volumes; l != NULL; l = l->next) -+ cur_volumes = g_list_prepend (cur_volumes, g_gdu_volume_get_presentable (G_GDU_VOLUME (l->data))); -+ -+ /* remove devices we want to ignore - we do it here so we get to reevaluate -+ * on the next update whether they should still be ignored -+ */ -+ new_volumes = gdu_pool_get_presentables (monitor->pool); -+ for (l = new_volumes; l != NULL; l = ll) -+ { -+ GduPresentable *p = GDU_PRESENTABLE (l->data); -+ ll = l->next; -+ if (!GDU_IS_VOLUME (p) || should_volume_be_ignored (monitor->pool, GDU_VOLUME (p), fstab_mount_points)) -+ { -+ g_object_unref (p); -+ new_volumes = g_list_delete_link (new_volumes, l); -+ } -+ } -+ -+ cur_volumes = g_list_sort (cur_volumes, (GCompareFunc) gdu_presentable_compare); -+ new_volumes = g_list_sort (new_volumes, (GCompareFunc) gdu_presentable_compare); -+ diff_sorted_lists (cur_volumes, -+ new_volumes, (GCompareFunc) gdu_presentable_compare, -+ &added, &removed); -+ -+ for (l = removed; l != NULL; l = l->next) -+ { -+ GduPresentable *p = GDU_PRESENTABLE (l->data); -+ GduDevice *d; -+ -+ d = gdu_presentable_get_device (p); -+ -+ volume = find_volume_for_device_file (monitor, gdu_device_get_device_file (d)); -+ if (volume != NULL) -+ { -+ /*g_debug ("removing volume %s", gdu_device_get_device_file (d));*/ -+ g_gdu_volume_removed (volume); -+ monitor->volumes = g_list_remove (monitor->volumes, volume); -+ *removed_volumes = g_list_prepend (*removed_volumes, volume); -+ } -+ g_object_unref (d); -+ } -+ -+ for (l = added; l != NULL; l = l->next) -+ { -+ GduPresentable *p = GDU_PRESENTABLE (l->data); -+ GduDevice *d; -+ -+ d = gdu_presentable_get_device (p); -+ -+ volume = find_volume_for_device_file (monitor, gdu_device_get_device_file (d)); -+ if (volume == NULL) -+ { -+ GduPresentable *toplevel_presentable; -+ -+ toplevel_presentable = gdu_presentable_get_toplevel (p); -+ if (toplevel_presentable != NULL) -+ { -+ GduDevice *toplevel_device; -+ -+ toplevel_device = gdu_presentable_get_device (toplevel_presentable); -+ drive = find_drive_by_device_file (monitor, gdu_device_get_device_file (toplevel_device)); -+ /*g_debug ("adding volume %s (drive %s)", -+ gdu_device_get_device_file (d), -+ gdu_device_get_device_file (toplevel_device));*/ -+ g_object_unref (toplevel_device); -+ g_object_unref (toplevel_presentable); -+ } -+ else -+ { -+ drive = NULL; -+ /*g_debug ("adding volume %s (no drive)", gdu_device_get_device_file (d));*/ -+ } -+ -+ volume = g_gdu_volume_new (G_VOLUME_MONITOR (monitor), -+ GDU_VOLUME (p), -+ drive, -+ NULL); -+ if (volume != NULL) -+ { -+ monitor->volumes = g_list_prepend (monitor->volumes, volume); -+ *added_volumes = g_list_prepend (*added_volumes, g_object_ref (volume)); -+ } -+ } -+ -+ g_object_unref (d); -+ } -+ -+ g_list_free (added); -+ g_list_free (removed); -+ -+ g_list_foreach (new_volumes, (GFunc) g_object_unref, NULL); -+ g_list_free (new_volumes); -+ -+ g_list_free (cur_volumes); -+ -+ g_list_foreach (fstab_mount_points, (GFunc) g_unix_mount_point_free, NULL); -+ g_list_free (fstab_mount_points); -+} -+ -+static void -+update_mounts (GGduVolumeMonitor *monitor, -+ GList **added_mounts, -+ GList **removed_mounts) -+{ -+ GList *new_mounts; -+ GList *removed, *added; -+ GList *l, *ll; -+ GGduMount *mount; -+ GGduVolume *volume; -+ const char *device_file; -+ const char *mount_path; -+ -+ new_mounts = g_unix_mounts_get (NULL); -+ -+ /* remove mounts we want to ignore - we do it here so we get to reevaluate -+ * on the next update whether they should still be ignored -+ */ -+ for (l = new_mounts; l != NULL; l = ll) -+ { -+ GUnixMountEntry *mount_entry = l->data; -+ ll = l->next; -+ -+ /* keep in sync with should_mount_be_ignored() */ -+ if (!g_unix_mount_guess_should_display (mount_entry)) -+ { -+ g_unix_mount_free (mount_entry); -+ new_mounts = g_list_delete_link (new_mounts, l); -+ } -+ } -+ -+ new_mounts = g_list_sort (new_mounts, (GCompareFunc) g_unix_mount_compare); -+ -+ diff_sorted_lists (monitor->last_mounts, -+ new_mounts, (GCompareFunc) g_unix_mount_compare, -+ &added, &removed); -+ -+ for (l = removed; l != NULL; l = l->next) -+ { -+ GUnixMountEntry *mount_entry = l->data; -+ -+ mount = find_mount_by_mount_path (monitor, g_unix_mount_get_mount_path (mount_entry)); -+ if (mount) -+ { -+ /*g_debug ("removing mount %s", g_unix_mount_get_device_path (mount_entry));*/ -+ g_gdu_mount_unmounted (mount); -+ monitor->mounts = g_list_remove (monitor->mounts, mount); -+ -+ *removed_mounts = g_list_prepend (*removed_mounts, mount); -+ } -+ } -+ -+ for (l = added; l != NULL; l = l->next) -+ { -+ GUnixMountEntry *mount_entry = l->data; -+ -+ device_file = g_unix_mount_get_device_path (mount_entry); -+ mount_path = g_unix_mount_get_mount_path (mount_entry); -+ volume = find_volume_for_device_file (monitor, device_file); -+ if (volume == NULL) -+ volume = find_volume_for_mount_path (monitor, mount_path); -+ -+ /*g_debug ("adding mount %s (vol %p)", g_unix_mount_get_device_path (mount_entry), volume);*/ -+ mount = g_gdu_mount_new (G_VOLUME_MONITOR (monitor), mount_entry, volume); -+ if (mount) -+ { -+ monitor->mounts = g_list_prepend (monitor->mounts, mount); -+ *added_mounts = g_list_prepend (*added_mounts, g_object_ref (mount)); -+ } -+ } -+ -+ g_list_free (added); -+ g_list_free (removed); -+ g_list_foreach (monitor->last_mounts, -+ (GFunc)g_unix_mount_free, NULL); -+ g_list_free (monitor->last_mounts); -+ monitor->last_mounts = new_mounts; -+} -+ -+static void -+update_discs (GGduVolumeMonitor *monitor, -+ GList **added_volumes, -+ GList **removed_volumes, -+ GList **added_mounts, -+ GList **removed_mounts) -+{ -+ GList *cur_discs; -+ GList *new_discs; -+ GList *removed, *added; -+ GList *l, *ll; -+ GGduDrive *drive; -+ GGduVolume *volume; -+ GGduMount *mount; -+ -+ /* we also need to generate GVolume + GMount objects for -+ * -+ * - optical discs that have audio -+ * - optical discs that are blank -+ * -+ */ -+ -+ cur_discs = NULL; -+ for (l = monitor->disc_volumes; l != NULL; l = l->next) -+ cur_discs = g_list_prepend (cur_discs, g_gdu_volume_get_presentable (G_GDU_VOLUME (l->data))); -+ -+ new_discs = gdu_pool_get_presentables (monitor->pool); -+ for (l = new_discs; l != NULL; l = ll) -+ { -+ GduPresentable *p = GDU_PRESENTABLE (l->data); -+ GduDevice *d; -+ gboolean ignore; -+ -+ ll = l->next; -+ ignore = TRUE; -+ -+ /* filter out everything but discs that are blank or has audio */ -+ d = gdu_presentable_get_device (p); -+ if (GDU_IS_VOLUME (p) && d != NULL && gdu_device_is_optical_disc (d)) -+ { -+ if (gdu_device_optical_disc_get_num_audio_tracks (d) > 0 || gdu_device_optical_disc_get_is_blank (d)) -+ ignore = FALSE; -+ } -+ -+ if (ignore) -+ { -+ g_object_unref (p); -+ new_discs = g_list_delete_link (new_discs, l); -+ } -+ -+ if (d != NULL) -+ g_object_unref (d); -+ } -+ -+ cur_discs = g_list_sort (cur_discs, (GCompareFunc) gdu_presentable_compare); -+ new_discs = g_list_sort (new_discs, (GCompareFunc) gdu_presentable_compare); -+ diff_sorted_lists (cur_discs, new_discs, (GCompareFunc) gdu_presentable_compare, &added, &removed); -+ -+ for (l = removed; l != NULL; l = l->next) -+ { -+ GduPresentable *p = GDU_PRESENTABLE (l->data); -+ GduDevice *d; -+ -+ d = gdu_presentable_get_device (p); -+ -+ volume = find_disc_volume_for_device_file (monitor, gdu_device_get_device_file (d)); -+ mount = find_disc_mount_for_volume (monitor, volume); -+ -+ if (mount != NULL) -+ { -+ /*g_debug ("removing disc mount %s", gdu_device_get_device_file (d));*/ -+ g_gdu_mount_unmounted (mount); -+ monitor->disc_mounts = g_list_remove (monitor->disc_mounts, mount); -+ *removed_mounts = g_list_prepend (*removed_mounts, mount); -+ } -+ -+ if (volume != NULL) -+ { -+ /*g_debug ("removing disc volume %s", gdu_device_get_device_file (d));*/ -+ g_gdu_volume_removed (volume); -+ monitor->disc_volumes = g_list_remove (monitor->disc_volumes, volume); -+ *removed_volumes = g_list_prepend (*removed_volumes, volume); -+ } -+ -+ g_object_unref (d); -+ } -+ -+ for (l = added; l != NULL; l = l->next) -+ { -+ GduPresentable *p = GDU_PRESENTABLE (l->data); -+ GduDevice *d; -+ gboolean is_blank; -+ -+ d = gdu_presentable_get_device (p); -+ -+ is_blank = gdu_device_optical_disc_get_is_blank (d); -+ -+ volume = find_disc_volume_for_device_file (monitor, gdu_device_get_device_file (d)); -+ if (volume == NULL) -+ { -+ GduPresentable *toplevel_presentable; -+ -+ toplevel_presentable = gdu_presentable_get_toplevel (p); -+ if (toplevel_presentable != NULL) -+ { -+ GduDevice *toplevel_device; -+ -+ toplevel_device = gdu_presentable_get_device (toplevel_presentable); -+ drive = find_drive_by_device_file (monitor, gdu_device_get_device_file (toplevel_device)); -+ /*g_debug ("adding volume %s (drive %s)", -+ gdu_device_get_device_file (d), -+ gdu_device_get_device_file (toplevel_device));*/ -+ g_object_unref (toplevel_device); -+ g_object_unref (toplevel_presentable); -+ } -+ else -+ { -+ drive = NULL; -+ /*g_debug ("adding volume %s (no drive)", gdu_device_get_device_file (d));*/ -+ } -+ -+ mount = NULL; -+ if (is_blank) -+ { -+ volume = g_gdu_volume_new (G_VOLUME_MONITOR (monitor), -+ GDU_VOLUME (p), -+ drive, -+ NULL); -+ mount = g_gdu_mount_new (G_VOLUME_MONITOR (monitor), -+ NULL, -+ volume); -+ } -+ else -+ { -+ gchar *uri; -+ gchar *device_basename; -+ GFile *activation_root; -+ -+ /* the gvfsd-cdda backend uses URI's like these */ -+ device_basename = g_path_get_basename (gdu_device_get_device_file (d)); -+ uri = g_strdup_printf ("cdda://%s", device_basename); -+ activation_root = g_file_new_for_uri (uri); -+ g_free (device_basename); -+ g_free (uri); -+ -+ volume = g_gdu_volume_new (G_VOLUME_MONITOR (monitor), -+ GDU_VOLUME (p), -+ drive, -+ activation_root); -+ -+ g_object_unref (activation_root); -+ } -+ -+ if (volume != NULL) -+ { -+ monitor->disc_volumes = g_list_prepend (monitor->disc_volumes, volume); -+ *added_volumes = g_list_prepend (*added_volumes, g_object_ref (volume)); -+ -+ if (mount != NULL) -+ { -+ monitor->disc_mounts = g_list_prepend (monitor->disc_mounts, mount); -+ *added_mounts = g_list_prepend (*added_mounts, g_object_ref (mount)); -+ } -+ } -+ } -+ -+ g_object_unref (d); -+ } -+ -+ g_list_free (added); -+ g_list_free (removed); -+ -+ g_list_foreach (new_discs, (GFunc) g_object_unref, NULL); -+ g_list_free (new_discs); -+ -+ g_list_free (cur_discs); -+} -diff --git a/monitor/gdu/ggduvolumemonitor.h b/monitor/gdu/ggduvolumemonitor.h -new file mode 100644 -index 0000000..ec559c4 ---- /dev/null -+++ b/monitor/gdu/ggduvolumemonitor.h -@@ -0,0 +1,60 @@ -+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -+/* gvfs - extensions for gio -+ * -+ * Copyright (C) 2006-2009 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., 59 Temple Place, Suite 330, -+ * Boston, MA 02111-1307, USA. -+ * -+ * Author: David Zeuthen -+ */ -+ -+#ifndef __G_GDU_VOLUME_MONITOR_H__ -+#define __G_GDU_VOLUME_MONITOR_H__ -+ -+#include -+#include -+#include -+ -+#include -+ -+G_BEGIN_DECLS -+ -+#define G_TYPE_GDU_VOLUME_MONITOR (g_gdu_volume_monitor_get_type ()) -+#define G_GDU_VOLUME_MONITOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_GDU_VOLUME_MONITOR, GGduVolumeMonitor)) -+#define G_GDU_VOLUME_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_GDU_VOLUME_MONITOR, GGduVolumeMonitorClass)) -+#define G_IS_GDU_VOLUME_MONITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_GDU_VOLUME_MONITOR)) -+#define G_IS_GDU_VOLUME_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_GDU_VOLUME_MONITOR)) -+ -+typedef struct _GGduVolumeMonitor GGduVolumeMonitor; -+typedef struct _GGduVolumeMonitorClass GGduVolumeMonitorClass; -+ -+/* Forward definitions */ -+typedef struct _GGduDrive GGduDrive; -+typedef struct _GGduVolume GGduVolume; -+typedef struct _GGduMount GGduMount; -+ -+struct _GGduVolumeMonitorClass { -+ GNativeVolumeMonitorClass parent_class; -+ -+}; -+ -+GType g_gdu_volume_monitor_get_type (void) G_GNUC_CONST; -+ -+GVolumeMonitor *g_gdu_volume_monitor_new (void); -+ -+G_END_DECLS -+ -+#endif /* __G_GDU_VOLUME_MONITOR_H__ */ -diff --git a/monitor/gdu/org.gtk.Private.GduVolumeMonitor.service.in b/monitor/gdu/org.gtk.Private.GduVolumeMonitor.service.in -new file mode 100644 -index 0000000..3fe4277 ---- /dev/null -+++ b/monitor/gdu/org.gtk.Private.GduVolumeMonitor.service.in -@@ -0,0 +1,3 @@ -+[D-BUS Service] -+Name=org.gtk.Private.GduVolumeMonitor -+Exec=@libexecdir@/gvfs-gdu-volume-monitor -diff --git a/monitor/gdu/polkit.c b/monitor/gdu/polkit.c -new file mode 100644 -index 0000000..5c37ba6 ---- /dev/null -+++ b/monitor/gdu/polkit.c -@@ -0,0 +1,137 @@ -+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -+/* gvfs - extensions for gio -+ * -+ * Copyright (C) 2006-2009 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., 59 Temple Place, Suite 330, -+ * Boston, MA 02111-1307, USA. -+ * -+ * Author: David Zeuthen -+ */ -+ -+#include -+#include -+ -+#include -+ -+#include "polkit.h" -+ -+static void -+_obtain_authz_cb (DBusMessage *reply, -+ GError *error, -+ gpointer user_data) -+{ -+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data); -+ gboolean gained_authz; -+ DBusError derror; -+ -+ if (error != NULL) { -+ g_simple_async_result_set_from_error (simple, error); -+ goto out; -+ } -+ -+ dbus_error_init (&derror); -+ if (!dbus_message_get_args (reply, -+ &derror, -+ DBUS_TYPE_BOOLEAN, &gained_authz, -+ DBUS_TYPE_INVALID)) -+ { -+ /* no need to translate; this only happens if the auth agent is buggy */ -+ g_simple_async_result_set_error (simple, -+ G_IO_ERROR, -+ G_IO_ERROR_FAILED, -+ "Error parsing reply for ObtainAuthorization(): %s: %s", -+ derror.name, derror.message); -+ dbus_error_free (&derror); -+ goto out; -+ } -+ -+ if (!gained_authz && error == NULL) -+ { -+ /* no need to translate, is never shown */ -+ g_simple_async_result_set_error (simple, -+ G_IO_ERROR, -+ G_IO_ERROR_FAILED_HANDLED, -+ "Didn't obtain authorization (bug in libgio user, it shouldn't display this error)"); -+ } -+ -+ out: -+ g_simple_async_result_complete (simple); -+ g_object_unref (simple); -+} -+ -+ -+gboolean -+_obtain_authz_finish (GAsyncResult *res, -+ GError **error) -+{ -+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res); -+ -+ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == _obtain_authz); -+ -+ if (g_simple_async_result_propagate_error (simple, error)) -+ return FALSE; -+ else -+ return TRUE; -+} -+ -+void -+_obtain_authz (const gchar *action_id, -+ GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data) -+{ -+ DBusConnection *connection; -+ DBusMessage *message; -+ GSimpleAsyncResult *simple; -+ guint xid; -+ guint pid; -+ DBusError derror; -+ -+ dbus_error_init (&derror); -+ -+ /* this connection is already integrated and guaranteed to exist, see gvfsproxyvolumemonitordaemon.c */ -+ connection = dbus_bus_get (DBUS_BUS_SESSION, &derror); -+ -+ simple = g_simple_async_result_new (NULL, -+ callback, -+ user_data, -+ _obtain_authz); -+ -+ message = dbus_message_new_method_call ("org.freedesktop.PolicyKit.AuthenticationAgent", /* bus name */ -+ "/", /* object */ -+ "org.freedesktop.PolicyKit.AuthenticationAgent", /* interface */ -+ "ObtainAuthorization"); -+ -+ xid = 0; -+ pid = getpid (); -+ -+ dbus_message_append_args (message, -+ DBUS_TYPE_STRING, -+ &(action_id), -+ DBUS_TYPE_UINT32, -+ &(xid), -+ DBUS_TYPE_UINT32, -+ &(pid), -+ DBUS_TYPE_INVALID); -+ -+ _g_dbus_connection_call_async (connection, -+ message, -+ -1, -+ (GAsyncDBusCallback) _obtain_authz_cb, -+ simple); -+ dbus_message_unref (message); -+ dbus_connection_unref (connection); -+} -diff --git a/monitor/gdu/polkit.h b/monitor/gdu/polkit.h -new file mode 100644 -index 0000000..4b26189 ---- /dev/null -+++ b/monitor/gdu/polkit.h -@@ -0,0 +1,44 @@ -+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -+/* gvfs - extensions for gio -+ * -+ * Copyright (C) 2006-2009 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., 59 Temple Place, Suite 330, -+ * Boston, MA 02111-1307, USA. -+ * -+ * Author: David Zeuthen -+ */ -+ -+ -+#ifndef __POLKIT_H__ -+#define __POLKIT_H__ -+ -+#include -+#include -+#include -+ -+G_BEGIN_DECLS -+ -+void _obtain_authz (const gchar *action_id, -+ GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data); -+ -+gboolean _obtain_authz_finish (GAsyncResult *res, -+ GError **error); -+ -+G_END_DECLS -+ -+#endif /* __POLKIT_H__ */ --- -1.6.2.2 - diff --git a/gdu-0002-Fix-how-we-determine-if-a-volume-is-ignored.patch b/gdu-0002-Fix-how-we-determine-if-a-volume-is-ignored.patch deleted file mode 100644 index 3cc470c..0000000 --- a/gdu-0002-Fix-how-we-determine-if-a-volume-is-ignored.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 94707c12442ed9ce099f110ec7089309133727ae Mon Sep 17 00:00:00 2001 -From: Tomas Bzatek -Date: Thu, 9 Apr 2009 19:03:16 -0400 -Subject: [PATCH 2/7] Fix how we determine if a volume is ignored - -This fixes a typo - wrong assignment of device file when testing whether the -volume should be ignored or not. It led to empty GVolume list associated to a -GDrive and thus inability to mount anything via computer:// - -Signed-off-by: David Zeuthen ---- - monitor/gdu/ggduvolumemonitor.c | 18 +++++++++--------- - 1 files changed, 9 insertions(+), 9 deletions(-) - -diff --git a/monitor/gdu/ggduvolumemonitor.c b/monitor/gdu/ggduvolumemonitor.c -index 32604d0..b52ee11 100644 ---- a/monitor/gdu/ggduvolumemonitor.c -+++ b/monitor/gdu/ggduvolumemonitor.c -@@ -617,7 +617,7 @@ get_mount_point_for_device (GduDevice *d, GList *fstab_mount_points) - for (l = fstab_mount_points; l != NULL; l = l->next) - { - GUnixMountPoint *mount_point = l->data; -- const gchar *device_file; -+ const gchar *fstab_device_file; - const gchar *fstab_mount_path; - - fstab_mount_path = g_unix_mount_point_get_mount_path (mount_point); -@@ -627,18 +627,18 @@ get_mount_point_for_device (GduDevice *d, GList *fstab_mount_points) - goto out; - } - -- device_file = g_unix_mount_point_get_device_path (mount_point); -- if (g_str_has_prefix (device_file, "LABEL=")) -+ fstab_device_file = g_unix_mount_point_get_device_path (mount_point); -+ if (g_str_has_prefix (fstab_device_file, "LABEL=")) - { -- if (g_strcmp0 (device_file + 6, gdu_device_id_get_label (d)) == 0) -+ if (g_strcmp0 (fstab_device_file + 6, gdu_device_id_get_label (d)) == 0) - { - ret = mount_point; - goto out; - } - } -- else if (g_str_has_prefix (device_file, "UUID=")) -+ else if (g_str_has_prefix (fstab_device_file, "UUID=")) - { -- if (g_ascii_strcasecmp (device_file + 5, gdu_device_id_get_uuid (d)) == 0) -+ if (g_ascii_strcasecmp (fstab_device_file + 5, gdu_device_id_get_uuid (d)) == 0) - { - ret = mount_point; - goto out; -@@ -646,11 +646,11 @@ get_mount_point_for_device (GduDevice *d, GList *fstab_mount_points) - } - else - { -- char resolved_device_file[PATH_MAX]; -+ char resolved_fstab_device_file[PATH_MAX]; - - /* handle symlinks such as /dev/disk/by-uuid/47C2-1994 */ -- if (realpath (device_file, resolved_device_file) != NULL && -- g_strcmp0 (resolved_device_file, device_file) == 0) -+ if (realpath (fstab_device_file, resolved_fstab_device_file) != NULL && -+ g_strcmp0 (resolved_fstab_device_file, device_file) == 0) - { - ret = mount_point; - goto out; --- -1.6.2.2 - diff --git a/gdu-0003-Avoid-automounting-volumes-on-virtual-and-unknown-bu.patch b/gdu-0003-Avoid-automounting-volumes-on-virtual-and-unknown-bu.patch deleted file mode 100644 index 741c2ce..0000000 --- a/gdu-0003-Avoid-automounting-volumes-on-virtual-and-unknown-bu.patch +++ /dev/null @@ -1,87 +0,0 @@ -From 47a663c7ad7b9de9942b9b740abff6610968a402 Mon Sep 17 00:00:00 2001 -From: David Zeuthen -Date: Thu, 9 Apr 2009 19:05:37 -0400 -Subject: [PATCH 3/7] Avoid automounting volumes on virtual and unknown buses - -Basically we want to avoid automounting volumes from - - 1. drives on a 'virtual' or unset bus - 2. volumes without a drive - -This is to avoid interference with things like Fedora's livecd-tools -that use device-mapper to set up images. See - - https://bugzilla.redhat.com/show_bug.cgi?id=494144 for more - -background. - -In the future we might want to relax 1. so automounting things like -Linux MD and LVM2 devices work. ---- - monitor/gdu/ggduvolume.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++ - 1 files changed, 50 insertions(+), 0 deletions(-) - -diff --git a/monitor/gdu/ggduvolume.c b/monitor/gdu/ggduvolume.c -index b540325..a5a3321 100644 ---- a/monitor/gdu/ggduvolume.c -+++ b/monitor/gdu/ggduvolume.c -@@ -293,6 +293,56 @@ update_volume (GGduVolume *volume) - volume->should_automount = FALSE; - } - -+ /* Avoid automounting volumes from -+ * -+ * 1. drives on a 'virtual' or unset bus -+ * 2. volumes without a drive -+ * -+ * This is to avoid interference with things like Fedora's -+ * livecd-tools that use device-mapper to set up images. See -+ * https://bugzilla.redhat.com/show_bug.cgi?id=494144 for more -+ * background. -+ * -+ * In the future we might want to relax 1. so automounting -+ * things like Linux MD and LVM2 devices work. -+ */ -+ if (volume->drive != NULL) -+ { -+ GduPresentable *drive_presentable; -+ drive_presentable = g_gdu_drive_get_presentable (volume->drive); -+ if (drive_presentable != NULL) -+ { -+ GduDevice *drive_device; -+ drive_device = gdu_presentable_get_device (drive_presentable); -+ if (drive_device != NULL) -+ { -+ const gchar *bus; -+ bus = gdu_device_drive_get_connection_interface (drive_device); -+ if (bus == NULL || strlen (bus) == 0 || g_strcmp0 (bus, "virtual") == 0) -+ { -+ volume->should_automount = FALSE; -+ } -+ g_object_unref (drive_device); -+ } -+ else -+ { -+ volume->should_automount = FALSE; -+ } -+ } -+ else -+ { -+ volume->should_automount = FALSE; -+ } -+ } -+ else -+ { -+ volume->should_automount = FALSE; -+ } -+ -+ g_debug ("should_automount = %d for %s", -+ volume->should_automount, -+ device != NULL ? gdu_device_get_device_file (device) : "(none)"); -+ - g_free (activation_uri); - } - --- -1.6.2.2 - diff --git a/gdu-0004-Remove-debug-spew.patch b/gdu-0004-Remove-debug-spew.patch deleted file mode 100644 index b9da41e..0000000 --- a/gdu-0004-Remove-debug-spew.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 82202f50bb76248f5a6368fe08de947758674acd Mon Sep 17 00:00:00 2001 -From: David Zeuthen -Date: Thu, 9 Apr 2009 19:14:25 -0400 -Subject: [PATCH 4/7] Remove debug spew - ---- - monitor/gdu/ggduvolume.c | 4 ---- - 1 files changed, 0 insertions(+), 4 deletions(-) - -diff --git a/monitor/gdu/ggduvolume.c b/monitor/gdu/ggduvolume.c -index a5a3321..6779f0f 100644 ---- a/monitor/gdu/ggduvolume.c -+++ b/monitor/gdu/ggduvolume.c -@@ -339,10 +339,6 @@ update_volume (GGduVolume *volume) - volume->should_automount = FALSE; - } - -- g_debug ("should_automount = %d for %s", -- volume->should_automount, -- device != NULL ? gdu_device_get_device_file (device) : "(none)"); -- - g_free (activation_uri); - } - --- -1.6.2.2 - diff --git a/gdu-0005-Don-t-add-a-volume-if-the-device-is-mounted-and-igno.patch b/gdu-0005-Don-t-add-a-volume-if-the-device-is-mounted-and-igno.patch deleted file mode 100644 index eea0e04..0000000 --- a/gdu-0005-Don-t-add-a-volume-if-the-device-is-mounted-and-igno.patch +++ /dev/null @@ -1,31 +0,0 @@ -From d9a00cc6172e2bf82f6825023c7a619be7f56747 Mon Sep 17 00:00:00 2001 -From: David Zeuthen -Date: Thu, 9 Apr 2009 19:33:35 -0400 -Subject: [PATCH 5/7] Don't add a volume if the device is mounted and ignored - -This fixes a problem where e.g. /dev/sdb1 a) is not referenced in -/etc/fstab; and b) is mounted in an ignored location e.g. /mnt/live. - -Specifically this bug affects the Fedora Live CD, see -https://bugzilla.redhat.com/show_bug.cgi?id=495033 for details. ---- - monitor/gdu/ggduvolumemonitor.c | 3 --- - 1 files changed, 0 insertions(+), 3 deletions(-) - -diff --git a/monitor/gdu/ggduvolumemonitor.c b/monitor/gdu/ggduvolumemonitor.c -index b52ee11..93aaf03 100644 ---- a/monitor/gdu/ggduvolumemonitor.c -+++ b/monitor/gdu/ggduvolumemonitor.c -@@ -671,9 +671,6 @@ should_mount_be_ignored (GduPool *pool, GduDevice *d) - - ret = FALSE; - -- if (gdu_device_is_mounted (d)) -- goto out; -- - mount_path = gdu_device_get_mount_path (d); - if (mount_path == NULL || strlen (mount_path) == 0) - goto out; --- -1.6.2.2 - diff --git a/gdu-0006-Ignore-drives-if-all-volumes-of-the-drive-are-ignore.patch b/gdu-0006-Ignore-drives-if-all-volumes-of-the-drive-are-ignore.patch deleted file mode 100644 index 2fa3232..0000000 --- a/gdu-0006-Ignore-drives-if-all-volumes-of-the-drive-are-ignore.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 346fdc3ddf383228ed58a48252e70919f6636b6e Mon Sep 17 00:00:00 2001 -From: David Zeuthen -Date: Thu, 9 Apr 2009 19:39:55 -0400 -Subject: [PATCH 6/7] Ignore drives if all volumes of the drive are ignored - ---- - monitor/gdu/ggduvolumemonitor.c | 16 +++++++++------- - 1 files changed, 9 insertions(+), 7 deletions(-) - -diff --git a/monitor/gdu/ggduvolumemonitor.c b/monitor/gdu/ggduvolumemonitor.c -index 93aaf03..9ecee8b 100644 ---- a/monitor/gdu/ggduvolumemonitor.c -+++ b/monitor/gdu/ggduvolumemonitor.c -@@ -763,15 +763,17 @@ should_drive_be_ignored (GduPool *pool, GduDrive *d, GList *fstab_mount_points) - - device = gdu_presentable_get_device (GDU_PRESENTABLE (d)); - -- /* the GduDevice for an activatable drive (such as RAID) is NULL if the drive is not -- * activated; never ignore these -+ /* If there is no GduDevice for a drive, then ignore it. -+ * -+ * Note that right now the only drives without a GduDevice are Linux -+ * MD arrays not yet activated. In the future we might want to -+ * display these so the user can start the array. - */ - if (device == NULL) -- goto out; -- -- /* never ignore drives with removable media */ -- if (gdu_device_is_removable (device)) -- goto out; -+ { -+ ret = TRUE; -+ goto out; -+ } - - has_volumes = FALSE; - all_volumes_are_ignored = TRUE; --- -1.6.2.2 - diff --git a/gdu-0007-Bug-576587-allow-eject-even-on-non-ejectable-vol.patch b/gdu-0007-Bug-576587-allow-eject-even-on-non-ejectable-vol.patch deleted file mode 100644 index 88999b5..0000000 --- a/gdu-0007-Bug-576587-allow-eject-even-on-non-ejectable-vol.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 303cfd43578f0a4198c063f1a5fbcd16fec2b0bf Mon Sep 17 00:00:00 2001 -From: David Zeuthen -Date: Thu, 9 Apr 2009 21:04:24 -0400 -Subject: [PATCH 7/7] =?utf-8?q?Bug=20576587=20=E2=80=93=20allow=20eject=20even=20on=20non-ejectable=20volumes?= -MIME-Version: 1.0 -Content-Type: text/plain; charset=utf-8 -Content-Transfer-Encoding: 8bit - -This fixes a host of problems with e.g. Kindle or iPod devices -requiring to be "ejected" to display messages such as - - "If you want to use your Kindle and continue charging, please eject - your Kindle from your computer." - -to the user. - -Previously we relied on HAL fdi files or similar to tag that such -devices needed to be ejectable. Now we just set everything as -ejectable. - -For this to really work well the Nautilus patch in - - http://bugzilla.gnome.org/show_bug.cgi?id=574067 - -needs to be reverted. ---- - monitor/gdu/ggdudrive.c | 6 +++++- - 1 files changed, 5 insertions(+), 1 deletions(-) - -diff --git a/monitor/gdu/ggdudrive.c b/monitor/gdu/ggdudrive.c -index 257a113..29e108d 100644 ---- a/monitor/gdu/ggdudrive.c -+++ b/monitor/gdu/ggdudrive.c -@@ -166,7 +166,11 @@ update_drive (GGduDrive *drive) - drive->device_file = g_strdup (gdu_device_get_device_file (device)); - drive->is_media_removable = gdu_device_is_removable (device); - drive->has_media = gdu_device_is_media_available (device); -- drive->can_eject = gdu_device_drive_get_is_media_ejectable (device) || gdu_device_drive_get_requires_eject (device); -+ /* All drives with removable media are ejectable -+ * -+ * See http://bugzilla.gnome.org/show_bug.cgi?id=576587 for why we want this. -+ */ -+ drive->can_eject = gdu_device_drive_get_is_media_ejectable (device) || gdu_device_drive_get_requires_eject (device) || gdu_device_is_removable (device); - drive->is_media_check_automatic = gdu_device_is_media_change_detected (device); - drive->can_poll_for_media = TRUE; - } --- -1.6.2.2 - diff --git a/gdu-0008-ignore-drives-without-volumes.patch b/gdu-0008-ignore-drives-without-volumes.patch deleted file mode 100644 index 362c96d..0000000 --- a/gdu-0008-ignore-drives-without-volumes.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 9a265228542de72df41caef8bd31402841ac389c Mon Sep 17 00:00:00 2001 -From: David Zeuthen -Date: Sat, 11 Apr 2009 12:43:06 -0400 -Subject: [PATCH] ignore drives without volumes - -This fixes a problem on some dmraid setups where we have drives -without any partitions (the dmraid boot scripts removes all partitions -(!)). See https://bugzilla.redhat.com/show_bug.cgi?id=495152 for more -details. - -This fix is also consistent with the policy of ignoring drives where -all volumes are ignored. E.g. prior to this patch we didn't shown -neither sdb if sdb1 was a the only unrecognized partition on sdb.. so -if you delete sdb1, it would be natural to keep hiding sdb (which is -what this patch does). ---- - monitor/gdu/ggduvolumemonitor.c | 8 +++++++- - 1 files changed, 7 insertions(+), 1 deletions(-) - -diff --git a/monitor/gdu/ggduvolumemonitor.c b/monitor/gdu/ggduvolumemonitor.c -index 9ecee8b..0e7ce6f 100644 ---- a/monitor/gdu/ggduvolumemonitor.c -+++ b/monitor/gdu/ggduvolumemonitor.c -@@ -799,7 +799,13 @@ should_drive_be_ignored (GduPool *pool, GduDrive *d, GList *fstab_mount_points) - } - } - -- ret = has_volumes && all_volumes_are_ignored; -+ /* we ignore a drive if -+ * -+ * a) it doesn't have any volumes; or -+ * -+ * b) the volumes of the drive are all ignored -+ */ -+ ret = (!has_volumes) || (has_volumes && all_volumes_are_ignored); - - out: - g_list_foreach (enclosed, (GFunc) g_object_unref, NULL); --- -1.6.2.2 - diff --git a/gdu-0009-never-ignore-drives-without-media.patch b/gdu-0009-never-ignore-drives-without-media.patch deleted file mode 100644 index 206aeb7..0000000 --- a/gdu-0009-never-ignore-drives-without-media.patch +++ /dev/null @@ -1,73 +0,0 @@ -From c54217a58f71f3ca7a85ce81fb96f363255c6110 Mon Sep 17 00:00:00 2001 -From: David Zeuthen -Date: Sat, 11 Apr 2009 12:57:55 -0400 -Subject: [PATCH] never ignore drives without media - ---- - monitor/gdu/ggduvolumemonitor.c | 21 +++++++++++++++------ - 1 files changed, 15 insertions(+), 6 deletions(-) - -diff --git a/monitor/gdu/ggduvolumemonitor.c b/monitor/gdu/ggduvolumemonitor.c -index 0e7ce6f..caa25a0 100644 ---- a/monitor/gdu/ggduvolumemonitor.c -+++ b/monitor/gdu/ggduvolumemonitor.c -@@ -751,13 +751,13 @@ static gboolean - should_drive_be_ignored (GduPool *pool, GduDrive *d, GList *fstab_mount_points) - { - GduDevice *device; -- gboolean ret; -+ gboolean ignored; - gboolean has_volumes; - gboolean all_volumes_are_ignored; - GList *enclosed; - GList *l; - -- ret = FALSE; -+ ignored = FALSE; - device = NULL; - enclosed = NULL; - -@@ -771,7 +771,7 @@ should_drive_be_ignored (GduPool *pool, GduDrive *d, GList *fstab_mount_points) - */ - if (device == NULL) - { -- ret = TRUE; -+ ignored = TRUE; - goto out; - } - -@@ -801,11 +801,20 @@ should_drive_be_ignored (GduPool *pool, GduDrive *d, GList *fstab_mount_points) - - /* we ignore a drive if - * -- * a) it doesn't have any volumes; or -+ * a) no volumes are available AND media is available; OR - * - * b) the volumes of the drive are all ignored - */ -- ret = (!has_volumes) || (has_volumes && all_volumes_are_ignored); -+ if (!has_volumes) -+ { -+ if (gdu_device_is_media_available (device)) -+ ignored = TRUE; -+ } -+ else -+ { -+ if (all_volumes_are_ignored) -+ ignored = TRUE; -+ } - - out: - g_list_foreach (enclosed, (GFunc) g_object_unref, NULL); -@@ -814,7 +823,7 @@ should_drive_be_ignored (GduPool *pool, GduDrive *d, GList *fstab_mount_points) - if (device != NULL) - g_object_unref (device); - -- return ret; -+ return ignored; - } - - static void --- -1.6.2.2 - diff --git a/gdu-0010-show-user-mountable-fstab-entries.patch b/gdu-0010-show-user-mountable-fstab-entries.patch deleted file mode 100644 index ab03218..0000000 --- a/gdu-0010-show-user-mountable-fstab-entries.patch +++ /dev/null @@ -1,876 +0,0 @@ -From 0f7a44dd0eac01f9783879af4ca3d3fe4a53af14 Mon Sep 17 00:00:00 2001 -From: David Zeuthen -Date: Mon, 13 Apr 2009 10:57:38 -0400 -Subject: [PATCH 10/13] show user-mountable fstab entries - -Show all entries from /etc/fstab for which - - - the entry is user mountable - - the mount point is in /media or $HOME - - if it's a /dev file make sure it exists and is not handled - by DeviceKit-disks already - -For example this /etc/fstab entry - - "quad.local:/media/FusionMedia /media/FusionMedia nfs defaults,users 0 0" - -makes Nautilus display this when unmounted - - http://people.freedesktop.org/~david/gvfs-user-mountable-fstab-entries.png - -and these GVolume and GMount objects to appear when mounted - - Volume(0): FusionMedia - Type: GProxyVolume (GProxyVolumeMonitorGdu) - themed icons: [folder-remote] [folder] - can_mount=1 - can_eject=0 - Mount(0): FusionMedia -> file:///media/FusionMedia - Type: GProxyMount (GProxyVolumeMonitorGdu) - themed icons: [folder-remote] [folder] - can_unmount=1 - can_eject=0 - is_shadowed=0 - -This should resolve http://bugzilla.gnome.org/show_bug.cgi?id=536292 ---- - monitor/gdu/ggdumount.c | 29 +++- - monitor/gdu/ggduvolume.c | 374 ++++++++++++++++++++++++++++++++++++--- - monitor/gdu/ggduvolume.h | 7 +- - monitor/gdu/ggduvolumemonitor.c | 174 ++++++++++++++++++- - 4 files changed, 548 insertions(+), 36 deletions(-) - -diff --git a/monitor/gdu/ggdumount.c b/monitor/gdu/ggdumount.c -index 27c22d9..e074a20 100644 ---- a/monitor/gdu/ggdumount.c -+++ b/monitor/gdu/ggdumount.c -@@ -696,8 +696,13 @@ g_gdu_mount_unmount (GMount *_mount, - { - GGduMount *mount = G_GDU_MOUNT (_mount); - GSimpleAsyncResult *simple; -+ GduPresentable *gdu_volume; - -- if (mount->volume == NULL) -+ gdu_volume = NULL; -+ if (mount->volume != NULL) -+ gdu_volume = g_gdu_volume_get_presentable_with_cleartext (mount->volume); -+ -+ if (mount->volume == NULL || gdu_volume == NULL) - { - gchar *argv[] = {"umount", NULL, NULL}; - -@@ -710,7 +715,7 @@ g_gdu_mount_unmount (GMount *_mount, - - eject_unmount_do (_mount, cancellable, callback, user_data, argv); - } -- else -+ else if (gdu_volume != NULL) - { - simple = g_simple_async_result_new (G_OBJECT (mount), - callback, -@@ -726,18 +731,25 @@ g_gdu_mount_unmount (GMount *_mount, - else - { - GduDevice *device; -- GduPresentable *volume; - - /* TODO: honor flags */ - -- volume = g_gdu_volume_get_presentable_with_cleartext (mount->volume); -- device = gdu_presentable_get_device (volume); -- -+ device = gdu_presentable_get_device (gdu_volume); - gdu_device_op_filesystem_unmount (device, unmount_cb, simple); -- - g_object_unref (device); - } - } -+ else -+ { -+ simple = g_simple_async_result_new_error (G_OBJECT (mount), -+ callback, -+ user_data, -+ G_IO_ERROR, -+ G_IO_ERROR_FAILED, -+ _("Operation not supported by backend")); -+ g_simple_async_result_complete (simple); -+ g_object_unref (simple); -+ } - } - - static gboolean -@@ -855,7 +867,8 @@ g_gdu_mount_guess_content_type_sync (GMount *_mount, - { - GduPresentable *presentable; - presentable = g_gdu_volume_get_presentable_with_cleartext (mount->volume); -- device = gdu_presentable_get_device (presentable); -+ if (presentable != NULL) -+ device = gdu_presentable_get_device (presentable); - } - - /* doesn't make sense to probe blank discs - look at the disc type instead */ -diff --git a/monitor/gdu/ggduvolume.c b/monitor/gdu/ggduvolume.c -index 6779f0f..49494a1 100644 ---- a/monitor/gdu/ggduvolume.c -+++ b/monitor/gdu/ggduvolume.c -@@ -35,12 +35,22 @@ - #include "ggduvolume.h" - #include "ggdumount.h" - -+/* for BUFSIZ */ -+#include -+ - #include "polkit.h" - - typedef struct MountOpData MountOpData; - - static void cancel_pending_mount_op (MountOpData *data); - -+static void g_gdu_volume_mount_unix_mount_point (GGduVolume *volume, -+ GMountMountFlags flags, -+ GMountOperation *mount_operation, -+ GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data); -+ - struct _GGduVolume - { - GObject parent; -@@ -49,8 +59,12 @@ struct _GGduVolume - GGduMount *mount; /* owned by volume monitor */ - GGduDrive *drive; /* owned by volume monitor */ - -+ /* only set if constructed via new() */ - GduVolume *gdu_volume; - -+ /* only set if constructed via new_for_unix_mount_point() */ -+ GUnixMountPoint *unix_mount_point; -+ - /* if the volume is encrypted, this is != NULL when unlocked */ - GduVolume *cleartext_gdu_volume; - -@@ -60,7 +74,7 @@ struct _GGduVolume - */ - MountOpData *pending_mount_op; - -- /* the following members need to be set upon construction */ -+ /* the following members need to be set upon construction, see constructors and update_volume() */ - GIcon *icon; - GFile *activation_root; - gchar *name; -@@ -110,6 +124,11 @@ g_gdu_volume_finalize (GObject *object) - g_object_unref (volume->gdu_volume); - } - -+ if (volume->unix_mount_point != NULL) -+ { -+ g_unix_mount_point_free (volume->unix_mount_point); -+ } -+ - if (volume->cleartext_gdu_volume != NULL) - { - g_signal_handlers_disconnect_by_func (volume->cleartext_gdu_volume, gdu_cleartext_volume_removed, volume); -@@ -174,6 +193,30 @@ update_volume (GGduVolume *volume) - - /* ---------------------------------------------------------------------------------------------------- */ - -+ /* if the volume is a fstab mount point, get the data from there */ -+ if (volume->unix_mount_point != NULL) -+ { -+ volume->can_mount = TRUE; -+ volume->should_automount = FALSE; -+ -+ g_free (volume->device_file); -+ volume->device_file = g_strdup (g_unix_mount_point_get_device_path (volume->unix_mount_point)); -+ -+ if (volume->icon != NULL) -+ g_object_unref (volume->icon); -+ if (g_strcmp0 (g_unix_mount_point_get_fs_type (volume->unix_mount_point), "nfs") == 0) -+ volume->icon = g_themed_icon_new_with_default_fallbacks ("folder-remote"); -+ else -+ volume->icon = g_unix_mount_point_guess_icon (volume->unix_mount_point); -+ -+ g_free (volume->name); -+ volume->name = g_unix_mount_point_guess_name (volume->unix_mount_point); -+ -+ //volume->can_eject = g_unix_mount_point_guess_can_eject (volume->unix_mount_point); -+ -+ goto update_done; -+ } -+ - /* in with the new */ - device = gdu_presentable_get_device (GDU_PRESENTABLE (volume->gdu_volume)); - pool = gdu_device_get_pool (device); -@@ -347,6 +390,8 @@ update_volume (GGduVolume *volume) - - /* ---------------------------------------------------------------------------------------------------- */ - -+ update_done: -+ - /* compute whether something changed */ - changed = !((old_can_mount == volume->can_mount) && - (old_should_automount == volume->should_automount) && -@@ -412,6 +457,23 @@ gdu_cleartext_volume_job_changed (GduPresentable *presentable, - } - - GGduVolume * -+g_gdu_volume_new_for_unix_mount_point (GVolumeMonitor *volume_monitor, -+ GUnixMountPoint *unix_mount_point) -+{ -+ GGduVolume *volume; -+ -+ volume = g_object_new (G_TYPE_GDU_VOLUME, NULL); -+ volume->volume_monitor = volume_monitor; -+ g_object_add_weak_pointer (G_OBJECT (volume_monitor), (gpointer) &(volume->volume_monitor)); -+ -+ volume->unix_mount_point = unix_mount_point; -+ -+ update_volume (volume); -+ -+ return volume; -+} -+ -+GGduVolume * - g_gdu_volume_new (GVolumeMonitor *volume_monitor, - GduVolume *gdu_volume, - GGduDrive *drive, -@@ -1084,6 +1146,18 @@ g_gdu_volume_mount (GVolume *_volume, - pool = NULL; - device = NULL; - -+ /* for fstab mounts, call the native mount command */ -+ if (volume->unix_mount_point != NULL) -+ { -+ g_gdu_volume_mount_unix_mount_point (volume, -+ flags, -+ mount_operation, -+ cancellable, -+ callback, -+ user_data); -+ goto out; -+ } -+ - if (volume->pending_mount_op != NULL) - { - simple = g_simple_async_result_new_error (G_OBJECT (volume), -@@ -1204,7 +1278,7 @@ g_gdu_volume_mount_finish (GVolume *volume, - { - GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result); - -- g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_gdu_volume_mount); -+ //g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_gdu_volume_mount); - - return !g_simple_async_result_propagate_error (simple, error); - } -@@ -1212,6 +1286,247 @@ g_gdu_volume_mount_finish (GVolume *volume, - /* ---------------------------------------------------------------------------------------------------- */ - - typedef struct { -+ GGduVolume *volume; -+ GAsyncReadyCallback callback; -+ gpointer user_data; -+ GCancellable *cancellable; -+ int error_fd; -+ GIOChannel *error_channel; -+ guint error_channel_source_id; -+ GString *error_string; -+ -+ guint wait_for_mount_timeout_id; -+ gulong wait_for_mount_changed_signal_handler_id; -+} MountPointOp; -+ -+static void -+mount_point_op_free (MountPointOp *data) -+{ -+ if (data->error_channel_source_id > 0) -+ g_source_remove (data->error_channel_source_id); -+ if (data->error_channel != NULL) -+ g_io_channel_unref (data->error_channel); -+ if (data->error_string != NULL) -+ g_string_free (data->error_string, TRUE); -+ if (data->error_fd > 0) -+ close (data->error_fd); -+ g_free (data); -+} -+ -+static void -+mount_point_op_changed_cb (GVolume *volume, -+ gpointer user_data) -+{ -+ MountPointOp *data = user_data; -+ GSimpleAsyncResult *simple; -+ -+ /* keep waiting if the mount hasn't appeared */ -+ if (data->volume->mount == NULL) -+ goto out; -+ -+ simple = g_simple_async_result_new (G_OBJECT (data->volume), -+ data->callback, -+ data->user_data, -+ NULL); -+ /* complete in idle to make sure the mount is added before we return */ -+ g_simple_async_result_complete_in_idle (simple); -+ g_object_unref (simple); -+ -+ g_signal_handler_disconnect (data->volume, data->wait_for_mount_changed_signal_handler_id); -+ g_source_remove (data->wait_for_mount_timeout_id); -+ -+ mount_point_op_free (data); -+ -+ out: -+ ; -+} -+ -+static gboolean -+mount_point_op_never_appeared_cb (gpointer user_data) -+{ -+ MountPointOp *data = user_data; -+ GSimpleAsyncResult *simple; -+ -+ simple = g_simple_async_result_new_error (G_OBJECT (data->volume), -+ data->callback, -+ data->user_data, -+ G_IO_ERROR, -+ G_IO_ERROR_FAILED, -+ "Timeout waiting for mount to appear"); -+ g_simple_async_result_complete (simple); -+ g_object_unref (simple); -+ -+ g_signal_handler_disconnect (data->volume, data->wait_for_mount_changed_signal_handler_id); -+ g_source_remove (data->wait_for_mount_timeout_id); -+ -+ mount_point_op_free (data); -+ -+ return FALSE; -+} -+ -+static void -+mount_point_op_cb (GPid pid, gint status, gpointer user_data) -+{ -+ MountPointOp *data = user_data; -+ GSimpleAsyncResult *simple; -+ -+ g_spawn_close_pid (pid); -+ -+ if (WEXITSTATUS (status) != 0) -+ { -+ GError *error; -+ error = g_error_new_literal (G_IO_ERROR, -+ G_IO_ERROR_FAILED, -+ data->error_string->str); -+ simple = g_simple_async_result_new_from_error (G_OBJECT (data->volume), -+ data->callback, -+ data->user_data, -+ error); -+ g_error_free (error); -+ g_simple_async_result_complete (simple); -+ g_object_unref (simple); -+ mount_point_op_free (data); -+ } -+ else -+ { -+ /* wait for the GMount to appear - this is to honor this requirement -+ * -+ * "If the mount operation succeeded, g_volume_get_mount() on -+ * volume is guaranteed to return the mount right after calling -+ * this function; there's no need to listen for the -+ * 'mount-added' signal on GVolumeMonitor." -+ * -+ * So we set up a signal handler waiting for it to appear. We also set up -+ * a timer for handling the case when it never appears. -+ */ -+ if (data->volume->mount == NULL) -+ { -+ /* no need to ref, GSimpleAsyncResult has a ref on data->volume */ -+ data->wait_for_mount_timeout_id = g_timeout_add (5 * 1000, -+ mount_point_op_never_appeared_cb, -+ data); -+ data->wait_for_mount_changed_signal_handler_id = g_signal_connect (data->volume, -+ "changed", -+ G_CALLBACK (mount_point_op_changed_cb), -+ data); -+ } -+ else -+ { -+ /* have the mount already, finish up */ -+ simple = g_simple_async_result_new (G_OBJECT (data->volume), -+ data->callback, -+ data->user_data, -+ NULL); -+ g_simple_async_result_complete (simple); -+ g_object_unref (simple); -+ mount_point_op_free (data); -+ } -+ } -+} -+ -+static gboolean -+mount_point_op_read_error (GIOChannel *channel, -+ GIOCondition condition, -+ gpointer user_data) -+{ -+ MountPointOp *data = user_data; -+ gchar buf[BUFSIZ]; -+ gsize bytes_read; -+ GError *error; -+ GIOStatus status; -+ -+ error = NULL; -+read: -+ status = g_io_channel_read_chars (channel, buf, sizeof (buf), &bytes_read, &error); -+ if (status == G_IO_STATUS_NORMAL) -+ { -+ g_string_append_len (data->error_string, buf, bytes_read); -+ if (bytes_read == sizeof (buf)) -+ goto read; -+ } -+ else if (status == G_IO_STATUS_EOF) -+ { -+ g_string_append_len (data->error_string, buf, bytes_read); -+ } -+ else if (status == G_IO_STATUS_ERROR) -+ { -+ if (data->error_string->len > 0) -+ g_string_append (data->error_string, "\n"); -+ -+ g_string_append (data->error_string, error->message); -+ g_error_free (error); -+ return FALSE; -+ } -+ -+ return TRUE; -+} -+ -+static void -+g_gdu_volume_mount_unix_mount_point (GGduVolume *volume, -+ GMountMountFlags flags, -+ GMountOperation *mount_operation, -+ GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data) -+{ -+ MountPointOp *data; -+ GPid child_pid; -+ GError *error; -+ const gchar *argv[] = {"mount", NULL, NULL}; -+ -+ argv[1] = g_unix_mount_point_get_mount_path (volume->unix_mount_point); -+ -+ data = g_new0 (MountPointOp, 1); -+ data->volume = volume; -+ data->callback = callback; -+ data->user_data = user_data; -+ data->cancellable = cancellable; -+ -+ error = NULL; -+ if (!g_spawn_async_with_pipes (NULL, /* working dir */ -+ (gchar **) argv, -+ NULL, /* envp */ -+ G_SPAWN_DO_NOT_REAP_CHILD|G_SPAWN_SEARCH_PATH, -+ NULL, /* child_setup */ -+ NULL, /* user_data for child_setup */ -+ &child_pid, -+ NULL, /* standard_input */ -+ NULL, /* standard_output */ -+ &(data->error_fd), -+ &error)) -+ { -+ g_assert (error != NULL); -+ goto handle_error; -+ } -+ -+ data->error_string = g_string_new (""); -+ -+ data->error_channel = g_io_channel_unix_new (data->error_fd); -+ g_io_channel_set_flags (data->error_channel, G_IO_FLAG_NONBLOCK, &error); -+ if (error != NULL) -+ goto handle_error; -+ -+ data->error_channel_source_id = g_io_add_watch (data->error_channel, G_IO_IN, mount_point_op_read_error, data); -+ g_child_watch_add (child_pid, mount_point_op_cb, data); -+ -+handle_error: -+ if (error != NULL) -+ { -+ GSimpleAsyncResult *simple; -+ simple = g_simple_async_result_new_from_error (G_OBJECT (data->volume), -+ data->callback, -+ data->user_data, -+ error); -+ g_simple_async_result_complete (simple); -+ g_object_unref (simple); -+ -+ mount_point_op_free (data); -+ } -+} -+ -+/* ---------------------------------------------------------------------------------------------------- */ -+ -+typedef struct { - GObject *object; - GAsyncReadyCallback callback; - gpointer user_data; -@@ -1300,19 +1615,22 @@ g_gdu_volume_get_identifier (GVolume *_volume, - - id = NULL; - -- device = gdu_presentable_get_device (GDU_PRESENTABLE (volume->gdu_volume)); -+ if (volume->gdu_volume != NULL) -+ { -+ device = gdu_presentable_get_device (GDU_PRESENTABLE (volume->gdu_volume)); - -- label = gdu_device_id_get_label (device); -- uuid = gdu_device_id_get_uuid (device); -+ label = gdu_device_id_get_label (device); -+ uuid = gdu_device_id_get_uuid (device); - -- g_object_unref (device); -+ g_object_unref (device); - -- if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE) == 0) -- id = g_strdup (volume->device_file); -- else if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_LABEL) == 0) -- id = strlen (label) > 0 ? g_strdup (label) : NULL; -- else if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_UUID) == 0) -- id = strlen (uuid) > 0 ? g_strdup (uuid) : NULL; -+ if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE) == 0) -+ id = g_strdup (volume->device_file); -+ else if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_LABEL) == 0) -+ id = strlen (label) > 0 ? g_strdup (label) : NULL; -+ else if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_UUID) == 0) -+ id = strlen (uuid) > 0 ? g_strdup (uuid) : NULL; -+ } - - return id; - } -@@ -1326,19 +1644,21 @@ g_gdu_volume_enumerate_identifiers (GVolume *_volume) - const gchar *label; - const gchar *uuid; - -- device = gdu_presentable_get_device (GDU_PRESENTABLE (volume->gdu_volume)); -- -- label = gdu_device_id_get_label (device); -- uuid = gdu_device_id_get_uuid (device); -- -- g_object_unref (device); -- - p = g_ptr_array_new (); -- g_ptr_array_add (p, g_strdup (G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE)); -- if (strlen (label) > 0) -- g_ptr_array_add (p, g_strdup (G_VOLUME_IDENTIFIER_KIND_LABEL)); -- if (strlen (uuid) > 0) -- g_ptr_array_add (p, g_strdup (G_VOLUME_IDENTIFIER_KIND_UUID)); -+ -+ if (volume->gdu_volume != NULL) -+ { -+ device = gdu_presentable_get_device (GDU_PRESENTABLE (volume->gdu_volume)); -+ label = gdu_device_id_get_label (device); -+ uuid = gdu_device_id_get_uuid (device); -+ g_object_unref (device); -+ -+ g_ptr_array_add (p, g_strdup (G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE)); -+ if (strlen (label) > 0) -+ g_ptr_array_add (p, g_strdup (G_VOLUME_IDENTIFIER_KIND_LABEL)); -+ if (strlen (uuid) > 0) -+ g_ptr_array_add (p, g_strdup (G_VOLUME_IDENTIFIER_KIND_UUID)); -+ } - - g_ptr_array_add (p, NULL); - -@@ -1452,3 +1772,9 @@ g_gdu_volume_get_presentable_with_cleartext (GGduVolume *volume) - - return GDU_PRESENTABLE (ret); - } -+ -+GUnixMountPoint * -+g_gdu_volume_get_unix_mount_point (GGduVolume *volume) -+{ -+ return volume->unix_mount_point; -+} -diff --git a/monitor/gdu/ggduvolume.h b/monitor/gdu/ggduvolume.h -index 8fd7358..a230d28 100644 ---- a/monitor/gdu/ggduvolume.h -+++ b/monitor/gdu/ggduvolume.h -@@ -50,6 +50,9 @@ GGduVolume *g_gdu_volume_new (GVolumeMonitor *volume_monitor, - GGduDrive *drive, - GFile *activation_root); - -+GGduVolume *g_gdu_volume_new_for_unix_mount_point (GVolumeMonitor *volume_monitor, -+ GUnixMountPoint *unix_mount_point); -+ - void g_gdu_volume_set_mount (GGduVolume *volume, - GGduMount *mount); - void g_gdu_volume_unset_mount (GGduVolume *volume, -@@ -69,10 +72,12 @@ gboolean g_gdu_volume_has_uuid (GGduVolume *volume, - gboolean g_gdu_volume_has_device_file (GGduVolume *volume, - const gchar *device_file); - --GduPresentable *g_gdu_volume_get_presentable (GGduVolume *volume); -+GduPresentable *g_gdu_volume_get_presentable (GGduVolume *volume); - - GduPresentable *g_gdu_volume_get_presentable_with_cleartext (GGduVolume *volume); - -+GUnixMountPoint *g_gdu_volume_get_unix_mount_point (GGduVolume *volume); -+ - G_END_DECLS - - #endif /* __G_GDU_VOLUME_H__ */ -diff --git a/monitor/gdu/ggduvolumemonitor.c b/monitor/gdu/ggduvolumemonitor.c -index caa25a0..67e2ec0 100644 ---- a/monitor/gdu/ggduvolumemonitor.c -+++ b/monitor/gdu/ggduvolumemonitor.c -@@ -51,6 +51,7 @@ struct _GGduVolumeMonitor { - - GList *drives; - GList *volumes; -+ GList *fstab_volumes; - GList *mounts; - - /* we keep volumes/mounts for blank and audio discs separate to handle e.g. mixed discs properly */ -@@ -80,6 +81,9 @@ static void update_drives (GGduVolumeMonitor *monitor, - static void update_volumes (GGduVolumeMonitor *monitor, - GList **added_volumes, - GList **removed_volumes); -+static void update_fstab_volumes (GGduVolumeMonitor *monitor, -+ GList **added_volumes, -+ GList **removed_volumes); - static void update_mounts (GGduVolumeMonitor *monitor, - GList **added_mounts, - GList **removed_mounts); -@@ -135,6 +139,7 @@ g_gdu_volume_monitor_finalize (GObject *object) - g_list_free (monitor->last_mounts); - - list_free (monitor->drives); -+ list_free (monitor->fstab_volumes); - list_free (monitor->volumes); - list_free (monitor->mounts); - -@@ -171,6 +176,8 @@ get_volumes (GVolumeMonitor *volume_monitor) - monitor = G_GDU_VOLUME_MONITOR (volume_monitor); - - l = g_list_copy (monitor->volumes); -+ ll = g_list_copy (monitor->fstab_volumes); -+ l = g_list_concat (l, ll); - ll = g_list_copy (monitor->disc_volumes); - l = g_list_concat (l, ll); - -@@ -211,6 +218,13 @@ get_volume_for_uuid (GVolumeMonitor *volume_monitor, const char *uuid) - goto found; - } - -+ for (l = monitor->fstab_volumes; l != NULL; l = l->next) -+ { -+ volume = l->data; -+ if (g_gdu_volume_has_uuid (volume, uuid)) -+ goto found; -+ } -+ - for (l = monitor->disc_volumes; l != NULL; l = l->next) - { - volume = l->data; -@@ -549,14 +563,49 @@ find_volume_for_mount_path (GGduVolumeMonitor *monitor, - for (l = monitor->volumes; l != NULL; l = l->next) - { - GGduVolume *volume = l->data; -+ if (g_gdu_volume_has_mount_path (volume, mount_path)) -+ { -+ found = volume; -+ goto out; -+ } -+ } - -+ for (l = monitor->fstab_volumes; l != NULL; l = l->next) -+ { -+ GGduVolume *volume = l->data; - if (g_gdu_volume_has_mount_path (volume, mount_path)) - { - found = volume; -- break; -+ goto out; - } - } - -+ out: -+ return found; -+} -+ -+static GGduVolume * -+find_volume_for_unix_mount_point (GGduVolumeMonitor *monitor, -+ GUnixMountPoint *unix_mount_point) -+{ -+ GList *l; -+ GGduVolume *found; -+ -+ found = NULL; -+ for (l = monitor->fstab_volumes; l != NULL; l = l->next) -+ { -+ GGduVolume *volume = l->data; -+ GUnixMountPoint *volume_mount_point; -+ -+ volume_mount_point = g_gdu_volume_get_unix_mount_point (volume); -+ if (g_unix_mount_point_compare (unix_mount_point, volume_mount_point) == 0) -+ { -+ found = volume; -+ goto out; -+ } -+ } -+ -+ out: - return found; - } - -@@ -859,6 +908,7 @@ update_all (GGduVolumeMonitor *monitor, - - update_drives (monitor, &added_drives, &removed_drives); - update_volumes (monitor, &added_volumes, &removed_volumes); -+ update_fstab_volumes (monitor, &added_volumes, &removed_volumes); - update_mounts (monitor, &added_mounts, &removed_mounts); - update_discs (monitor, - &added_volumes, &removed_volumes, -@@ -935,16 +985,34 @@ find_volume_for_device_file (GGduVolumeMonitor *monitor, - const gchar *device_file) - { - GList *l; -+ GGduVolume *ret; - -+ ret = NULL; - for (l = monitor->volumes; l != NULL; l = l->next) - { - GGduVolume *volume = G_GDU_VOLUME (l->data); - - if (g_gdu_volume_has_device_file (volume, device_file)) -- return volume; -+ { -+ ret = volume; -+ goto out; -+ } - } - -- return NULL; -+ ret = NULL; -+ for (l = monitor->fstab_volumes; l != NULL; l = l->next) -+ { -+ GGduVolume *volume = G_GDU_VOLUME (l->data); -+ -+ if (g_gdu_volume_has_device_file (volume, device_file)) -+ { -+ ret = volume; -+ goto out; -+ } -+ } -+ -+ out: -+ return ret; - } - - static GGduDrive * -@@ -1189,6 +1257,106 @@ update_volumes (GGduVolumeMonitor *monitor, - } - - static void -+update_fstab_volumes (GGduVolumeMonitor *monitor, -+ GList **added_volumes, -+ GList **removed_volumes) -+{ -+ GList *fstab_mount_points; -+ GList *cur_fstab_mount_points; -+ GList *new_fstab_mount_points; -+ GList *removed, *added; -+ GList *l; -+ GGduVolume *volume; -+ -+ fstab_mount_points = g_unix_mount_points_get (NULL); -+ -+ cur_fstab_mount_points = NULL; -+ for (l = monitor->fstab_volumes; l != NULL; l = l->next) -+ cur_fstab_mount_points = g_list_prepend (cur_fstab_mount_points, g_gdu_volume_get_unix_mount_point (G_GDU_VOLUME (l->data))); -+ -+ new_fstab_mount_points = NULL; -+ for (l = fstab_mount_points; l != NULL; l = l->next) -+ { -+ GUnixMountPoint *mount_point = l->data; -+ const gchar *device_file; -+ -+ /* only show user mountable mount points */ -+ if (!g_unix_mount_point_is_user_mountable (mount_point)) -+ continue; -+ -+ /* only show stuff that can be mounted in user-visible locations */ -+ if (!_g_unix_mount_point_guess_should_display (mount_point)) -+ continue; -+ -+ /* ignore mount point if the device doesn't exist or is handled by DeviceKit-disks */ -+ device_file = g_unix_mount_point_get_device_path (mount_point); -+ if (g_str_has_prefix (device_file, "/dev/")) -+ { -+ gchar resolved_path[PATH_MAX]; -+ GduDevice *device; -+ -+ /* doesn't exist */ -+ if (realpath (device_file, resolved_path) != 0) -+ continue; -+ -+ /* is handled by DKD */ -+ device = gdu_pool_get_by_device_file (monitor->pool, resolved_path); -+ if (device != NULL) -+ { -+ g_object_unref (device); -+ continue; -+ } -+ } -+ -+ new_fstab_mount_points = g_list_prepend (new_fstab_mount_points, mount_point); -+ } -+ -+ diff_sorted_lists (cur_fstab_mount_points, -+ new_fstab_mount_points, (GCompareFunc) g_unix_mount_point_compare, -+ &added, &removed); -+ -+ for (l = removed; l != NULL; l = l->next) -+ { -+ GUnixMountPoint *mount_point = l->data; -+ volume = find_volume_for_unix_mount_point (monitor, mount_point); -+ if (volume != NULL) -+ { -+ g_gdu_volume_removed (volume); -+ monitor->fstab_volumes = g_list_remove (monitor->fstab_volumes, volume); -+ *removed_volumes = g_list_prepend (*removed_volumes, volume); -+ /*g_debug ("removed volume for /etc/fstab mount point %s", g_unix_mount_point_get_mount_path (mount_point));*/ -+ } -+ } -+ -+ for (l = added; l != NULL; l = l->next) -+ { -+ GUnixMountPoint *mount_point = l->data; -+ -+ volume = g_gdu_volume_new_for_unix_mount_point (G_VOLUME_MONITOR (monitor), mount_point); -+ if (volume != NULL) -+ { -+ /* steal mount_point since g_gdu_volume_new_for_unix_mount_point() takes ownership of it */ -+ fstab_mount_points = g_list_remove (fstab_mount_points, mount_point); -+ monitor->fstab_volumes = g_list_prepend (monitor->fstab_volumes, volume); -+ *added_volumes = g_list_prepend (*added_volumes, g_object_ref (volume)); -+ /*g_debug ("added volume for /etc/fstab mount point %s", g_unix_mount_point_get_mount_path (mount_point));*/ -+ } -+ else -+ { -+ g_unix_mount_point_free (mount_point); -+ } -+ } -+ -+ g_list_free (added); -+ g_list_free (removed); -+ -+ g_list_free (cur_fstab_mount_points); -+ -+ g_list_foreach (fstab_mount_points, (GFunc) g_unix_mount_point_free, NULL); -+ g_list_free (fstab_mount_points); -+} -+ -+static void - update_mounts (GGduVolumeMonitor *monitor, - GList **added_mounts, - GList **removed_mounts) --- -1.6.2.2 - diff --git a/gdu-0011-Bug-576083-pre-unmount-signals-not-being-trigger.patch b/gdu-0011-Bug-576083-pre-unmount-signals-not-being-trigger.patch deleted file mode 100644 index c199c06..0000000 --- a/gdu-0011-Bug-576083-pre-unmount-signals-not-being-trigger.patch +++ /dev/null @@ -1,326 +0,0 @@ -From 8d9fc8a777fb1b00ae371e276a14416a0987f4af Mon Sep 17 00:00:00 2001 -From: David Zeuthen -Date: Mon, 13 Apr 2009 14:20:15 -0400 -Subject: [PATCH 11/13] =?utf-8?q?Bug=20576083=20=E2=80=93=20pre-unmount=20signals=20not=20being=20triggered?= -MIME-Version: 1.0 -Content-Type: text/plain; charset=utf-8 -Content-Transfer-Encoding: 8bit - -Basically emit GVolumeMonitor::mount-pre-unmount on the volume monitor -and retry unmount operation a couple of times. ---- - monitor/gdu/ggdumount.c | 177 +++++++++++++++++++++++++++++++++++++--------- - 1 files changed, 142 insertions(+), 35 deletions(-) - -diff --git a/monitor/gdu/ggdumount.c b/monitor/gdu/ggdumount.c -index e074a20..78088d5 100644 ---- a/monitor/gdu/ggdumount.c -+++ b/monitor/gdu/ggdumount.c -@@ -38,6 +38,9 @@ - #include "ggdumount.h" - #include "ggduvolume.h" - -+#define BUSY_UNMOUNT_NUM_ATTEMPTS 5 -+#define BUSY_UNMOUNT_MS_DELAY_BETWEEN_ATTEMPTS 500 -+ - struct _GGduMount - { - GObject parent; -@@ -451,26 +454,52 @@ g_gdu_mount_can_eject (GMount *_mount) - - typedef struct { - GMount *mount; -+ -+ gchar **argv; -+ guint num_attempts_left; -+ - GAsyncReadyCallback callback; - gpointer user_data; - GCancellable *cancellable; -+ - int error_fd; - GIOChannel *error_channel; - guint error_channel_source_id; - GString *error_string; --} UnmountEjectOp; -+ -+} UnmountOp; -+ -+static gboolean unmount_attempt (UnmountOp *data); - - static void --eject_unmount_cb (GPid pid, gint status, gpointer user_data) -+unmount_cb (GPid pid, gint status, gpointer user_data) - { -- UnmountEjectOp *data = user_data; -+ UnmountOp *data = user_data; - GSimpleAsyncResult *simple; - -+ g_spawn_close_pid (pid); -+ - if (WEXITSTATUS (status) != 0) - { - GError *error; -+ gint error_code; -+ -+ error_code = G_IO_ERROR_FAILED; -+ /* we may want to add more strstr() checks here depending on what unmount helper is being used etc... */ -+ if (data->error_string->str != NULL && strstr (data->error_string->str, "is busy") != NULL) -+ error_code = G_IO_ERROR_BUSY; -+ -+ if (error_code == G_IO_ERROR_BUSY && data->num_attempts_left > 0) -+ { -+ g_timeout_add (BUSY_UNMOUNT_MS_DELAY_BETWEEN_ATTEMPTS, -+ (GSourceFunc) unmount_attempt, -+ data); -+ data->num_attempts_left -= 1; -+ goto out; -+ } -+ - error = g_error_new_literal (G_IO_ERROR, -- G_IO_ERROR_FAILED, -+ error_code, - data->error_string->str); - simple = g_simple_async_result_new_from_error (G_OBJECT (data->mount), - data->callback, -@@ -493,16 +522,19 @@ eject_unmount_cb (GPid pid, gint status, gpointer user_data) - g_io_channel_unref (data->error_channel); - g_string_free (data->error_string, TRUE); - close (data->error_fd); -- g_spawn_close_pid (pid); -+ g_strfreev (data->argv); - g_free (data); -+ -+ out: -+ ; - } - - static gboolean --eject_unmount_read_error (GIOChannel *channel, -- GIOCondition condition, -- gpointer user_data) -+unmount_read_error (GIOChannel *channel, -+ GIOCondition condition, -+ gpointer user_data) - { -- UnmountEjectOp *data = user_data; -+ UnmountOp *data = user_data; - gchar buf[BUFSIZ]; - gsize bytes_read; - GError *error; -@@ -532,26 +564,15 @@ read: - return TRUE; - } - --static void --eject_unmount_do (GMount *mount, -- GCancellable *cancellable, -- GAsyncReadyCallback callback, -- gpointer user_data, -- char **argv) -+static gboolean -+unmount_attempt (UnmountOp *data) - { -- UnmountEjectOp *data; - GPid child_pid; - GError *error; - -- data = g_new0 (UnmountEjectOp, 1); -- data->mount = mount; -- data->callback = callback; -- data->user_data = user_data; -- data->cancellable = cancellable; -- - error = NULL; - if (!g_spawn_async_with_pipes (NULL, /* working dir */ -- argv, -+ data->argv, - NULL, /* envp */ - G_SPAWN_DO_NOT_REAP_CHILD|G_SPAWN_SEARCH_PATH, - NULL, /* child_setup */ -@@ -572,8 +593,8 @@ eject_unmount_do (GMount *mount, - if (error != NULL) - goto handle_error; - -- data->error_channel_source_id = g_io_add_watch (data->error_channel, G_IO_IN, eject_unmount_read_error, data); -- g_child_watch_add (child_pid, eject_unmount_cb, data); -+ data->error_channel_source_id = g_io_add_watch (data->error_channel, G_IO_IN, unmount_read_error, data); -+ g_child_watch_add (child_pid, unmount_cb, data); - - handle_error: - -@@ -596,6 +617,28 @@ handle_error: - g_error_free (error); - g_free (data); - } -+ -+ return FALSE; -+} -+ -+static void -+unmount_do (GMount *mount, -+ GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data, -+ char **argv) -+{ -+ UnmountOp *data; -+ -+ data = g_new0 (UnmountOp, 1); -+ data->mount = mount; -+ data->callback = callback; -+ data->user_data = user_data; -+ data->cancellable = cancellable; -+ data->num_attempts_left = BUSY_UNMOUNT_NUM_ATTEMPTS; -+ data->argv = g_strdupv (argv); -+ -+ unmount_attempt (data); - } - - /* ---------------------------------------------------------------------------------------------------- */ -@@ -619,19 +662,54 @@ luks_lock_cb (GduDevice *device, - g_object_unref (simple); - } - -+static gboolean gdu_unmount_attempt (GSimpleAsyncResult *simple); -+ - static void --unmount_cb (GduDevice *device, -- GError *error, -- gpointer user_data) -+gdu_unmount_cb (GduDevice *device, -+ GError *error, -+ gpointer user_data) - { - GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data); - - if (error != NULL) - { -+ gint error_code; -+ -+ /*g_debug ("domain=%s error_code=%d '%s'", g_quark_to_string (error->domain), error->code, error->message);*/ -+ -+ error_code = G_IO_ERROR_FAILED; -+ if (error->domain == GDU_ERROR && error->code == GDU_ERROR_BUSY) -+ error_code = G_IO_ERROR_BUSY; -+ - /* We could handle PolicyKit integration here but this action is allowed by default - * and this won't be needed when porting to PolicyKit 1.0 anyway - */ -- g_simple_async_result_set_from_error (simple, error); -+ -+ if (error_code == G_IO_ERROR_BUSY) -+ { -+ guint num_attempts_left; -+ -+ num_attempts_left = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (simple), "num-attempts-left")); -+ -+ if (num_attempts_left > 0) -+ { -+ num_attempts_left -= 1; -+ g_object_set_data (G_OBJECT (simple), -+ "num-attempts-left", -+ GUINT_TO_POINTER (num_attempts_left)); -+ -+ g_timeout_add (BUSY_UNMOUNT_MS_DELAY_BETWEEN_ATTEMPTS, -+ (GSourceFunc) gdu_unmount_attempt, -+ simple); -+ goto out; -+ } -+ } -+ -+ g_simple_async_result_set_error (simple, -+ G_IO_ERROR, -+ error_code, -+ "%s", -+ error->message); - g_error_free (error); - g_simple_async_result_complete (simple); - g_object_unref (simple); -@@ -687,6 +765,17 @@ unmount_cb (GduDevice *device, - ; - } - -+static gboolean -+gdu_unmount_attempt (GSimpleAsyncResult *simple) -+{ -+ GduDevice *device; -+ -+ /* TODO: honor flags */ -+ device = g_object_get_data (G_OBJECT (simple), "gdu-device"); -+ gdu_device_op_filesystem_unmount (device, gdu_unmount_cb, simple); -+ return FALSE; -+} -+ - static void - g_gdu_mount_unmount (GMount *_mount, - GMountUnmountFlags flags, -@@ -698,6 +787,21 @@ g_gdu_mount_unmount (GMount *_mount, - GSimpleAsyncResult *simple; - GduPresentable *gdu_volume; - -+ /* emit the ::mount-pre-unmount signal */ -+ g_signal_emit_by_name (mount->volume_monitor, "mount-pre-unmount", mount); -+ -+ /* If we end up with G_IO_ERROR_BUSY, try again BUSY_UNMOUNT_NUM_ATTEMPTS times -+ * waiting BUSY_UNMOUNT_MS_DELAY_BETWEEN_ATTEMPTS milliseconds between each -+ * attempt. -+ * -+ * This is to give other processes recieving the ::mount-pre-unmount signal some -+ * time to close file descriptors. -+ * -+ * TODO: Unfortunately this code is a bit messy because we take two different -+ * codepaths depending on whether we use GDU or the native unmount command. -+ * It would be good to clean this up. -+ */ -+ - gdu_volume = NULL; - if (mount->volume != NULL) - gdu_volume = g_gdu_volume_get_presentable_with_cleartext (mount->volume); -@@ -713,7 +817,7 @@ g_gdu_mount_unmount (GMount *_mount, - else - argv[1] = mount->device_file; - -- eject_unmount_do (_mount, cancellable, callback, user_data, argv); -+ unmount_do (_mount, cancellable, callback, user_data, argv); - } - else if (gdu_volume != NULL) - { -@@ -722,6 +826,10 @@ g_gdu_mount_unmount (GMount *_mount, - user_data, - NULL); - -+ g_object_set_data (G_OBJECT (simple), -+ "num-attempts-left", -+ GUINT_TO_POINTER (BUSY_UNMOUNT_NUM_ATTEMPTS)); -+ - if (mount->is_burn_mount) - { - /* burn mounts are really never mounted... */ -@@ -731,12 +839,9 @@ g_gdu_mount_unmount (GMount *_mount, - else - { - GduDevice *device; -- -- /* TODO: honor flags */ -- - device = gdu_presentable_get_device (gdu_volume); -- gdu_device_op_filesystem_unmount (device, unmount_cb, simple); -- g_object_unref (device); -+ g_object_set_data_full (G_OBJECT (simple), "gdu-device", device, g_object_unref); -+ gdu_unmount_attempt (simple); - } - } - else -@@ -760,6 +865,8 @@ g_gdu_mount_unmount_finish (GMount *mount, - return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error); - } - -+/* ---------------------------------------------------------------------------------------------------- */ -+ - typedef struct { - GObject *object; - GAsyncReadyCallback callback; --- -1.6.2.2 - diff --git a/gdu-0012-use-new-gnome-disk-utility-API-to-hide-unwanted-devi.patch b/gdu-0012-use-new-gnome-disk-utility-API-to-hide-unwanted-devi.patch deleted file mode 100644 index 10b287f..0000000 --- a/gdu-0012-use-new-gnome-disk-utility-API-to-hide-unwanted-devi.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 2bce9f36bd365be284c10af6a1f74c6120adc3e8 Mon Sep 17 00:00:00 2001 -From: David Zeuthen -Date: Wed, 15 Apr 2009 11:33:36 -0400 -Subject: [PATCH 12/13] use new gnome-disk-utility API to hide unwanted devices - -This is to resolve bugs like - - https://bugzilla.redhat.com/show_bug.cgi?id=495170 ---- - monitor/gdu/ggduvolumemonitor.c | 12 ++++++++++++ - 1 files changed, 12 insertions(+), 0 deletions(-) - -diff --git a/monitor/gdu/ggduvolumemonitor.c b/monitor/gdu/ggduvolumemonitor.c -index 67e2ec0..2c1f727 100644 ---- a/monitor/gdu/ggduvolumemonitor.c -+++ b/monitor/gdu/ggduvolumemonitor.c -@@ -720,6 +720,12 @@ should_mount_be_ignored (GduPool *pool, GduDevice *d) - - ret = FALSE; - -+ if (gdu_device_get_presentation_hide (d)) -+ { -+ ret = TRUE; -+ goto out; -+ } -+ - mount_path = gdu_device_get_mount_path (d); - if (mount_path == NULL || strlen (mount_path) == 0) - goto out; -@@ -751,6 +757,9 @@ should_volume_be_ignored (GduPool *pool, GduVolume *volume, GList *fstab_mount_p - - device = gdu_presentable_get_device (GDU_PRESENTABLE (volume)); - -+ if (gdu_device_get_presentation_hide (device)) -+ goto out; -+ - usage = gdu_device_id_get_usage (device); - type = gdu_device_id_get_type (device); - -@@ -824,6 +833,9 @@ should_drive_be_ignored (GduPool *pool, GduDrive *d, GList *fstab_mount_points) - goto out; - } - -+ if (gdu_device_get_presentation_hide (device)) -+ goto out; -+ - has_volumes = FALSE; - all_volumes_are_ignored = TRUE; - --- -1.6.2.2 - diff --git a/gdu-0013-pass-the-flush-mount-option-for-vfat.patch b/gdu-0013-pass-the-flush-mount-option-for-vfat.patch deleted file mode 100644 index f86384d..0000000 --- a/gdu-0013-pass-the-flush-mount-option-for-vfat.patch +++ /dev/null @@ -1,99 +0,0 @@ -From 7fd9061afbd0ec4664adb17aed706e12fd5f3eee Mon Sep 17 00:00:00 2001 -From: David Zeuthen -Date: Wed, 15 Apr 2009 14:41:27 -0400 -Subject: [PATCH 13/13] pass the 'flush' mount option for vfat - -This mount option makes the vfat filesystem driver flush data more -often. As a consequence - - 1. users never get to see the gnome-disk-utility notification daemon - dialog just added - - http://people.freedesktop.org/~david/gdu-unmount-busy-1.png - - but that's useful for other filesystems as well. - - 2. The Nautilus copy dialog stays up until things are on the disk - -We do this in gvfs rather than DeviceKit-disks because in some -scenarios 'flush' may be unwanted and there is currently no way to -turn it off (e.g. no 'noflush' or 'flush=0' option). - -Ideally the kernel would get this kind of thing right by itself. ---- - monitor/gdu/ggduvolume.c | 36 +++++++++++++++++++++++++++++++++--- - 1 files changed, 33 insertions(+), 3 deletions(-) - -diff --git a/monitor/gdu/ggduvolume.c b/monitor/gdu/ggduvolume.c -index 49494a1..871a1c5 100644 ---- a/monitor/gdu/ggduvolume.c -+++ b/monitor/gdu/ggduvolume.c -@@ -648,6 +648,27 @@ g_gdu_volume_get_mount (GVolume *volume) - - /* ---------------------------------------------------------------------------------------------------- */ - -+static gchar ** -+get_mount_options (GduDevice *device) -+{ -+ gchar **ret; -+ -+ /* one day we might read this from user settings */ -+ if (g_strcmp0 (gdu_device_id_get_usage (device), "filesystem") == 0 && -+ g_strcmp0 (gdu_device_id_get_type (device), "vfat") == 0) -+ { -+ ret = g_new0 (gchar *, 2); -+ ret[0] = g_strdup ("flush"); -+ ret[1] = NULL; -+ } -+ else -+ ret = NULL; -+ -+ return ret; -+} -+ -+/* ---------------------------------------------------------------------------------------------------- */ -+ - struct MountOpData - { - GGduVolume *volume; -@@ -735,8 +756,11 @@ mount_obtain_authz_cb (GObject *source_object, - } - else - { -+ gchar **mount_options; - /* got the authz, now try again */ -- gdu_device_op_filesystem_mount (data->device_to_mount, mount_cb, data); -+ mount_options = get_mount_options (data->device_to_mount); -+ gdu_device_op_filesystem_mount (data->device_to_mount, mount_options, mount_cb, data); -+ g_strfreev (mount_options); - goto out; - } - -@@ -842,7 +866,10 @@ mount_cleartext_device (MountOpData *data, - } - else - { -- gdu_device_op_filesystem_mount (data->device_to_mount, mount_cb, data); -+ gchar **mount_options; -+ mount_options = get_mount_options (data->device_to_mount); -+ gdu_device_op_filesystem_mount (data->device_to_mount, mount_options, mount_cb, data); -+ g_strfreev (mount_options); - } - - g_object_unref (pool); -@@ -1260,8 +1287,11 @@ g_gdu_volume_mount (GVolume *_volume, - } - else - { -+ gchar **mount_options; - data->device_to_mount = g_object_ref (device); -- gdu_device_op_filesystem_mount (data->device_to_mount, mount_cb, data); -+ mount_options = get_mount_options (data->device_to_mount); -+ gdu_device_op_filesystem_mount (data->device_to_mount, mount_options, mount_cb, data); -+ g_strfreev (mount_options); - } - - out: --- -1.6.2.2 - diff --git a/gvfs-1.2.3-cdda-allow-query-well-formed-filenames-only.patch b/gvfs-1.2.3-cdda-allow-query-well-formed-filenames-only.patch deleted file mode 100644 index 03af1e2..0000000 --- a/gvfs-1.2.3-cdda-allow-query-well-formed-filenames-only.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 5073d2736d6a83de04e749ae5952071da3d1ccbc Mon Sep 17 00:00:00 2001 -From: Tomas Bzatek -Date: Tue, 12 May 2009 15:17:06 +0200 -Subject: [PATCH 4/4] CDDA: allow query well-formed filenames only - -This will check for ".wav" suffix as long as sscanf() -doesn't care of the rest of the formatting string after -last placeholder. Querying filenames like -"Track 10.nonsense" will now throw an error. - -Partially fixes https://bugzilla.redhat.com/show_bug.cgi?id=499266 ---- - daemon/gvfsbackendcdda.c | 3 ++- - 1 files changed, 2 insertions(+), 1 deletions(-) - -diff --git a/daemon/gvfsbackendcdda.c b/daemon/gvfsbackendcdda.c -index c97aa44..9b30753 100644 ---- a/daemon/gvfsbackendcdda.c -+++ b/daemon/gvfsbackendcdda.c -@@ -460,7 +460,8 @@ get_track_num_from_name (GVfsBackendCdda *cdda_backend, const char *filename) - char *basename; - - basename = g_path_get_basename (filename); -- if (sscanf (basename, "Track %d.wav", &n) == 1) -+ if (sscanf (basename, "Track %d.wav", &n) == 1 && -+ g_str_has_suffix (basename, ".wav")) - { - g_free (basename); - return n; --- -1.6.2.2 - diff --git a/gvfs.spec b/gvfs.spec index 1f3498c..831dd74 100644 --- a/gvfs.spec +++ b/gvfs.spec @@ -1,14 +1,14 @@ Summary: Backends for the gio framework in GLib Name: gvfs Version: 1.3.1 -Release: 1%{?dist} +Release: 2%{?dist} License: LGPLv2+ Group: System Environment/Libraries URL: http://www.gtk.org Source: http://download.gnome.org/sources/gvfs/1.3/gvfs-%{version}.tar.bz2 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: pkgconfig -BuildRequires: glib2-devel >= 2.19.2 +BuildRequires: glib2-devel >= 2.21.2 BuildRequires: dbus-glib-devel BuildRequires: /usr/bin/ssh BuildRequires: libcdio-devel >= 0.78.2 @@ -19,10 +19,10 @@ BuildRequires: gnome-keyring-devel BuildRequires: intltool BuildRequires: gettext-devel BuildRequires: GConf2-devel -BuildRequires: gnome-disk-utility-devel >= 0.3 +BuildRequires: gnome-disk-utility-devel >= 0.4 # This is a hack until the xfce4-notifyd dependency issue is fixed # https://fedorahosted.org/rel-eng/ticket/1788 -BuildRequires: notification-daemon +#BuildRequires: notification-daemon Requires(post): desktop-file-utils @@ -40,6 +40,18 @@ Patch8: gvfs-1.2.2-dnssd-deadlock.patch # https://bugzilla.redhat.com/show_bug.cgi?id=504339 Patch9: gvfs-1.2.3-sftp-40sec-timeout.patch + +# Backports from trunk +Patch100: 0001-FTP-prepare-the-code-for-active-FTP-support.patch +Patch101: 0002-FTP-Bug-516704-Be-able-to-connect-to-an-Active-FTP-S.patch +Patch102: 0004-FTP-add-the-error-code-for-EPRT-s-522-error.patch +Patch103: 0005-FTP-add-EPRT-support.patch +Patch104: 0006-Bug-582772-gvfsd-computer-crashes-with-SEGSEV-in-rec.patch +Patch105: 0007-Better-handling-of-PC-floppy-drives.patch +Patch106: 0008-FTP-use-the-EPRT-feature-response-for-EPRT-support-n.patch +Patch107: 0009-FTP-remove-EPSV-as-default-feature.patch + + %description The gvfs package provides backend implementations for the gio framework in GLib. It includes ftp, sftp, cifs. @@ -126,6 +138,15 @@ media players (Media Transfer Protocol) to applications using gvfs. %patch8 -p1 -b .dnssd-deadlock %patch9 -p1 -b .sftp-timeout +%patch100 -p1 +%patch101 -p1 +%patch102 -p1 +%patch103 -p1 +%patch104 -p1 +%patch105 -p1 +%patch106 -p1 +%patch107 -p1 + %build # Needed for gvfs-0.2.1-archive-integration.patch @@ -268,6 +289,10 @@ update-desktop-database &> /dev/null ||: %changelog +* Mon Jun 22 2009 Tomas Bzatek - 1.3.1-2 +- Bump version requirements +- Backport FTP and Computer backend patches from master + * Mon Jun 15 2009 Matthias Clasen - 1.3.1-1 - Update to 1.3.1 - Drop obsolete patches