some sftp fixes
- From: Dave Camp <dave ximian com>
- To: gnome-vfs-list gnome org
- Subject: some sftp fixes
- Date: Mon, 08 Mar 2004 01:36:08 -0500
the attached patch fixes some thread safety problems, some refcounting
problems, and a misused g_hash_table_foreach.
ok to commit?
-dave
? gnome-vfs-sftp-fixes.patch
? libgnomevfs/gnome-vfs-enum-types.c
? libgnomevfs/gnome-vfs-enum-types.h
? libgnomevfs/s-enum-types-c
? libgnomevfs/s-enum-types-h
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/gnome-vfs/ChangeLog,v
retrieving revision 1.1761
diff -u -r1.1761 ChangeLog
--- ChangeLog 7 Mar 2004 21:08:16 -0000 1.1761
+++ ChangeLog 8 Mar 2004 06:19:55 -0000
@@ -1,3 +1,14 @@
+2004-03-08 Dave Camp <dave ximian com>
+
+ * modules/sftp-method.c: (sftp_connect), (sftp_get_connection),
+ (sftp_connection_close), (sftp_connection_ref),
+ (close_and_remove_connection), (sftp_connection_unref), (do_open),
+ (do_create), (do_write), (do_get_file_info), (do_open_directory),
+ (do_make_directory), (do_remove_directory), (do_move), (do_rename),
+ (do_unlink), (do_set_file_info), (do_create_symlink),
+ (close_thunk), (vfs_module_shutdown): Fix some threadsafety and
+ refcounting problems.
+
2004-03-07 Christophe Fergeau <teuf gnome org>
* libgnomevfs/gnome-vfs-utils.c: (gnome_vfs_get_volume_free_space):
Index: modules/sftp-method.c
===================================================================
RCS file: /cvs/gnome/gnome-vfs/modules/sftp-method.c,v
retrieving revision 1.3
diff -u -r1.3 sftp-method.c
--- modules/sftp-method.c 1 Mar 2004 09:29:12 -0000 1.3
+++ modules/sftp-method.c 8 Mar 2004 06:20:00 -0000
@@ -111,6 +111,8 @@
static GHashTable *sftp_connection_table = NULL;
+G_LOCK_DEFINE_STATIC (sftp_connection_table);
+
#define SFTP_CONNECTION(p) ((SftpConnection *) (p))
#define SFTP_OPEN_HANDLE(p) ((SftpOpenHandle *) (p))
@@ -151,6 +153,8 @@
GnomeVFSFileInfoOptions options,
GnomeVFSContext *context);
+static void sftp_connection_ref (SftpConnection *connection);
+
static gboolean sftp_connection_process_errors (GIOChannel *channel,
GIOCondition cond,
GnomeVFSResult *status);
@@ -1103,6 +1107,7 @@
if (!g_thread_supported ()) g_thread_init (NULL);
*connection = g_new0 (SftpConnection, 1);
+ (*connection)->ref_count = 1;
(*connection)->in_fd = in_fd;
(*connection)->out_fd = out_fd;
(*connection)->error_channel = error_channel;
@@ -1146,6 +1151,8 @@
g_return_val_if_fail (connection != NULL, GNOME_VFS_ERROR_INTERNAL);
g_return_val_if_fail (uri != NULL, GNOME_VFS_ERROR_INTERNAL);
+ G_LOCK (sftp_connection_table);
+
if (sftp_connection_table == NULL)
sftp_connection_table = g_hash_table_new
(g_str_hash, g_str_equal);
@@ -1193,6 +1200,7 @@
__FUNCTION__));
g_mutex_lock ((*connection)->mutex);
+ sftp_connection_ref ((*connection));
DEBUG (g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s: Lock acquired",
__FUNCTION__));
@@ -1201,6 +1209,8 @@
res = GNOME_VFS_OK;
}
+ G_UNLOCK (sftp_connection_table);
+
return res;
}
@@ -1215,7 +1225,6 @@
g_io_channel_shutdown (conn->error_channel, FALSE, NULL);
g_io_channel_unref (conn->error_channel);
- g_hash_table_remove (sftp_connection_table, conn->hash_name);
g_free (conn->hash_name);
g_free (conn);
@@ -1313,21 +1322,49 @@
g_mutex_unlock (conn->mutex);
}
+/* caller must have a lock on the connection */
static void
sftp_connection_ref (SftpConnection *conn)
{
++conn->ref_count;
- if (conn->close_timeout_id > 0)
+ if (conn->close_timeout_id > 0) {
g_source_remove (conn->close_timeout_id);
+ conn->close_timeout_id = 0;
+ }
}
+static gboolean
+close_and_remove_connection (SftpConnection *conn)
+{
+ sftp_connection_lock (conn);
+
+ conn->close_timeout_id = 0;
+
+ if (conn->ref_count != 0) {
+ sftp_connection_unlock (conn);
+ return FALSE;
+ }
+
+ G_LOCK (sftp_connection_table);
+ g_hash_table_remove (sftp_connection_table, conn->hash_name);
+ G_UNLOCK (sftp_connection_table);
+
+ sftp_connection_unlock (conn);
+
+ sftp_connection_close (conn);
+
+ return FALSE;
+}
+
+/* caller must have a lock on the connection */
static void
sftp_connection_unref (SftpConnection *conn)
{
- if (--conn->ref_count == 0)
+ if (--conn->ref_count == 0 && conn->close_timeout_id == 0) {
conn->close_timeout_id
- = g_timeout_add (SFTP_CLOSE_TIMEOUT, (GSourceFunc) sftp_connection_close, conn);
+ = g_timeout_add (SFTP_CLOSE_TIMEOUT, (GSourceFunc) close_and_remove_connection, conn);
+ }
}
@@ -1423,8 +1460,6 @@
res = sftp_get_connection (&conn, uri);
if (res != GNOME_VFS_OK) return res;
- sftp_connection_ref (conn);
-
path = gnome_vfs_unescape_string (gnome_vfs_uri_get_path (uri), NULL);
id = sftp_connection_get_id (conn);
@@ -1451,18 +1486,23 @@
sftp_res = iobuf_read_handle (conn->in_fd, &sftp_handle, id, &sftp_handle_len);
- sftp_connection_unlock (conn);
-
if (sftp_res == SSH2_FX_OK) {
handle = g_new0 (SftpOpenHandle, 1);
handle->sftp_handle = sftp_handle;
handle->sftp_handle_len = sftp_handle_len;
handle->connection = conn;
*method_handle = (GnomeVFSMethodHandle *) handle;
+
+ sftp_connection_unlock (conn);
+
DEBUG (g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s: Exit", __FUNCTION__));
return GNOME_VFS_OK;
} else {
*method_handle = NULL;
+
+ sftp_connection_unref (conn);
+ sftp_connection_unlock (conn);
+
DEBUG (g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s: Exit", __FUNCTION__));
return sftp_status_to_vfs_result (sftp_res);
}
@@ -1496,8 +1536,6 @@
res = sftp_get_connection (&conn, uri);
if (res != GNOME_VFS_OK) return res;
- sftp_connection_ref (conn);
-
path = gnome_vfs_unescape_string (gnome_vfs_uri_get_path (uri), NULL);
id = sftp_connection_get_id (conn);
@@ -1525,7 +1563,6 @@
sftp_res = iobuf_read_handle (conn->in_fd, &sftp_handle, id, &sftp_handle_len);
- sftp_connection_unlock (conn);
if (sftp_res == SSH2_FX_OK) {
handle = g_new0 (SftpOpenHandle, 1);
@@ -1533,10 +1570,17 @@
handle->sftp_handle_len = sftp_handle_len;
handle->connection = conn;
*method_handle = (GnomeVFSMethodHandle *) handle;
+
+ sftp_connection_unlock (conn);
+
DEBUG (g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s: Exit", __FUNCTION__));
return GNOME_VFS_OK;
} else {
*method_handle = NULL;
+
+ sftp_connection_unref (conn);
+ sftp_connection_unlock (conn);
+
DEBUG (g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s: Exit", __FUNCTION__));
return sftp_status_to_vfs_result (sftp_res);
}
@@ -1843,6 +1887,7 @@
if (status != SSH2_FX_OK) {
buffer_free (&msg);
g_free (write_req);
+ sftp_connection_unlock (handle->connection);
return sftp_status_to_vfs_result (status);
}
@@ -1942,8 +1987,11 @@
if (options & GNOME_VFS_FILE_INFO_FOLLOW_LINKS) {
res = get_real_path (conn, path, &real_path);
- if (res != GNOME_VFS_OK)
+ if (res != GNOME_VFS_OK) {
+ sftp_connection_unref (conn);
+ sftp_connection_unlock (conn);
return res;
+ }
}
else
real_path = path;
@@ -1963,6 +2011,7 @@
res = iobuf_read_file_info (conn->in_fd, file_info, id);
+ sftp_connection_unref (conn);
sftp_connection_unlock (conn);
if (res == GNOME_VFS_OK) {
@@ -2063,8 +2112,6 @@
sftp_res = iobuf_read_handle (conn->in_fd, &sftp_handle, id, &sftp_handle_len);
- sftp_connection_unlock (conn);
-
DEBUG (g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s: Result is %d", __FUNCTION__, sftp_res));
if (sftp_res == SSH2_FX_OK) {
@@ -2077,6 +2124,9 @@
handle->info_read_ptr = 0;
handle->info_write_ptr = 0;
*method_handle = (GnomeVFSMethodHandle *) handle;
+
+ sftp_connection_unlock (conn);
+
DEBUG (g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s: Opened directory %p",
__FUNCTION__, handle));
DEBUG (g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s: Exit", __FUNCTION__));
@@ -2086,6 +2136,9 @@
if (sftp_res == SSH2_FX_EOF)
sftp_res = SSH2_FX_NO_SUCH_FILE;
+ sftp_connection_unref (conn);
+ sftp_connection_unlock (conn);
+
*method_handle = NULL;
DEBUG (g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s: Exit", __FUNCTION__));
return sftp_status_to_vfs_result (sftp_res);
@@ -2286,6 +2339,7 @@
res = sftp_status_to_vfs_result (iobuf_read_result (conn->in_fd, id));
+ sftp_connection_unref (conn);
sftp_connection_unlock (conn);
return res;
@@ -2314,6 +2368,7 @@
res = sftp_status_to_vfs_result (iobuf_read_result (conn->in_fd, id));
+ sftp_connection_unref (conn);
sftp_connection_unlock (conn);
return res;
@@ -2356,6 +2411,7 @@
res = sftp_status_to_vfs_result (iobuf_read_result (conn->in_fd, id));
+ sftp_connection_unref (conn);
sftp_connection_unlock (conn);
return res;
@@ -2400,6 +2456,7 @@
res = sftp_status_to_vfs_result (iobuf_read_result (conn->in_fd, id));
+ sftp_connection_unref (conn);
sftp_connection_unlock (conn);
return res;
@@ -2427,6 +2484,7 @@
res = sftp_status_to_vfs_result (iobuf_read_result (conn->in_fd, id));
+ sftp_connection_unref (conn);
sftp_connection_unlock (conn);
return res;
@@ -2496,6 +2554,7 @@
res = sftp_status_to_vfs_result (iobuf_read_result (conn->in_fd, id));
+ sftp_connection_unref (conn);
sftp_connection_unlock (conn);
}
@@ -2522,9 +2581,12 @@
res = sftp_get_connection (&conn, uri);
if (res != GNOME_VFS_OK) return res;
- if (conn->version < 3)
+ if (conn->version < 3) {
+ sftp_connection_unref (conn);
+ sftp_connection_unlock (conn);
return GNOME_VFS_ERROR_NOT_SUPPORTED;
-
+ }
+
buffer_init (&msg);
path = gnome_vfs_unescape_string (gnome_vfs_uri_get_path (uri), NULL);
@@ -2542,6 +2604,7 @@
res = sftp_status_to_vfs_result (iobuf_read_result (conn->in_fd, id));
+ sftp_connection_unref (conn);
sftp_connection_unlock (conn);
return res;
@@ -2589,13 +2652,15 @@
close_thunk (gpointer key, gpointer value, gpointer user_data)
{
sftp_connection_close (SFTP_CONNECTION (value));
- return FALSE;
+ return TRUE;
}
void
vfs_module_shutdown (GnomeVFSMethod *method)
{
- g_hash_table_foreach (sftp_connection_table, (GHFunc) close_thunk, NULL);
+ G_LOCK (sftp_connection_table);
+ g_hash_table_foreach_remove (sftp_connection_table, (GHRFunc) close_thunk, NULL);
+ G_UNLOCK (sftp_connection_table);
if (inited_buffers != 0)
g_critical ("%d buffers leaked", inited_buffers);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]