- Bump version requirements

- Backport FTP and Computer backend patches from master
This commit is contained in:
Tomas Bzatek 2009-06-22 12:40:51 +00:00
parent 23deddcfda
commit 32d84ada85
25 changed files with 954 additions and 7145 deletions

View File

@ -0,0 +1,205 @@
From 7f2ac23d150aa779310a37534fc8564bbfc93b86 Mon Sep 17 00:00:00 2001
From: Benjamin Otte <otte@gnome.org>
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

View File

@ -0,0 +1,361 @@
From 2839922c259b848d7689d245a055c628754dc116 Mon Sep 17 00:00:00 2001
From: Benjamin Otte <otte@gnome.org>
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 <config.h>
+#include "gvfsftpconnection.h"
+
#include <string.h>
#include <glib/gi18n.h>
-#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

View File

@ -0,0 +1,27 @@
From 81fb75b2dc11a969d890f58bc3255ceae3f7bfde Mon Sep 17 00:00:00 2001
From: Benjamin Otte <otte@gnome.org>
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

View File

@ -0,0 +1,101 @@
From 19a6bf345fdb8d445e4c3683e4ca0af0a0031f0b Mon Sep 17 00:00:00 2001
From: Benjamin Otte <otte@gnome.org>
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

View File

@ -0,0 +1,36 @@
From 5d3ab40b5b0a574f207e7177d2f4c3bd329458a4 Mon Sep 17 00:00:00 2001
From: David Zeuthen <davidz@redhat.com>
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

View File

@ -0,0 +1,117 @@
From c6405c6653c27b247f1fbb59c01b95938fb6b2d8 Mon Sep 17 00:00:00 2001
From: David Zeuthen <davidz@redhat.com>
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

View File

@ -0,0 +1,51 @@
From acb3f8029d9f9a7054e3f138fd978e24233573a3 Mon Sep 17 00:00:00 2001
From: Benjamin Otte <otte@gnome.org>
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

View File

@ -0,0 +1,27 @@
From 056cfe684e3db4f83c176bb723c264ecfe60837f Mon Sep 17 00:00:00 2001
From: Benjamin Otte <otte@gnome.org>
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

View File

@ -1,59 +0,0 @@
From 3f3f21fe6e2bdac8fd6acf048da6fb228adde092 Mon Sep 17 00:00:00 2001
From: David Zeuthen <davidz@redhat.com>
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

View File

@ -1,29 +0,0 @@
From 59dd3b33a71a930651f23142e2a7d7e57727144f Mon Sep 17 00:00:00 2001
From: David Zeuthen <davidz@redhat.com>
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

File diff suppressed because it is too large Load Diff

View File

@ -1,69 +0,0 @@
From 94707c12442ed9ce099f110ec7089309133727ae Mon Sep 17 00:00:00 2001
From: Tomas Bzatek <tbzatek@redhat.com>
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 <davidz@redhat.com>
---
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

View File

@ -1,87 +0,0 @@
From 47a663c7ad7b9de9942b9b740abff6610968a402 Mon Sep 17 00:00:00 2001
From: David Zeuthen <davidz@redhat.com>
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

View File

@ -1,27 +0,0 @@
From 82202f50bb76248f5a6368fe08de947758674acd Mon Sep 17 00:00:00 2001
From: David Zeuthen <davidz@redhat.com>
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

View File

@ -1,31 +0,0 @@
From d9a00cc6172e2bf82f6825023c7a619be7f56747 Mon Sep 17 00:00:00 2001
From: David Zeuthen <davidz@redhat.com>
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

View File

@ -1,41 +0,0 @@
From 346fdc3ddf383228ed58a48252e70919f6636b6e Mon Sep 17 00:00:00 2001
From: David Zeuthen <davidz@redhat.com>
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

View File

@ -1,49 +0,0 @@
From 303cfd43578f0a4198c063f1a5fbcd16fec2b0bf Mon Sep 17 00:00:00 2001
From: David Zeuthen <davidz@redhat.com>
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

View File

@ -1,41 +0,0 @@
From 9a265228542de72df41caef8bd31402841ac389c Mon Sep 17 00:00:00 2001
From: David Zeuthen <davidz@redhat.com>
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

View File

@ -1,73 +0,0 @@
From c54217a58f71f3ca7a85ce81fb96f363255c6110 Mon Sep 17 00:00:00 2001
From: David Zeuthen <davidz@redhat.com>
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

View File

@ -1,876 +0,0 @@
From 0f7a44dd0eac01f9783879af4ca3d3fe4a53af14 Mon Sep 17 00:00:00 2001
From: David Zeuthen <davidz@redhat.com>
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 <stdio.h>
+
#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

View File

@ -1,326 +0,0 @@
From 8d9fc8a777fb1b00ae371e276a14416a0987f4af Mon Sep 17 00:00:00 2001
From: David Zeuthen <davidz@redhat.com>
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

View File

@ -1,52 +0,0 @@
From 2bce9f36bd365be284c10af6a1f74c6120adc3e8 Mon Sep 17 00:00:00 2001
From: David Zeuthen <davidz@redhat.com>
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

View File

@ -1,99 +0,0 @@
From 7fd9061afbd0ec4664adb17aed706e12fd5f3eee Mon Sep 17 00:00:00 2001
From: David Zeuthen <davidz@redhat.com>
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

View File

@ -1,32 +0,0 @@
From 5073d2736d6a83de04e749ae5952071da3d1ccbc Mon Sep 17 00:00:00 2001
From: Tomas Bzatek <tbzatek@redhat.com>
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

View File

@ -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 <tbzatek@redhat.com> - 1.3.1-2
- Bump version requirements
- Backport FTP and Computer backend patches from master
* Mon Jun 15 2009 Matthias Clasen <mclasen@redhat.com> - 1.3.1-1
- Update to 1.3.1
- Drop obsolete patches