--- gvfs-0-2-3/client/gvfsfusedaemon.c 2008-05-23 14:24:07.000000000 -0500 +++ gvfs-2-22/client/gvfsfusedaemon.c 2008-05-23 14:17:36.000000000 -0500 @@ -55,8 +55,8 @@ #define DEBUG_ENABLED 0 -#define GET_FILE_HANDLE(fi) (GUINT_TO_POINTER ((guint) (fi)->fh)) -#define SET_FILE_HANDLE(fi, fh) ((fi)->fh = (guint64) GPOINTER_TO_UINT (fh)) +#define GET_FILE_HANDLE(fi) ((gpointer) (fi)->fh) +#define SET_FILE_HANDLE(fi, fh) ((fi)->fh = (guint64) (fh)) typedef struct { time_t creation_time; @@ -71,7 +71,10 @@ typedef enum { } FileOp; typedef struct { + gint refcount; + GMutex *mutex; + gchar *path; FileOp op; gpointer stream; gint length; @@ -183,18 +186,45 @@ errno_from_error (GError *error) } static FileHandle * -file_handle_new (void) +file_handle_new (const gchar *path) { FileHandle *file_handle; file_handle = g_new0 (FileHandle, 1); + file_handle->refcount = 1; file_handle->mutex = g_mutex_new (); file_handle->op = FILE_OP_NONE; + file_handle->path = g_strdup (path); + + return file_handle; +} +static FileHandle * +file_handle_ref (FileHandle *file_handle) +{ + g_atomic_int_inc (&file_handle->refcount); return file_handle; } static void +file_handle_unref (FileHandle *file_handle) +{ + if (g_atomic_int_dec_and_test (&file_handle->refcount)) + { + g_static_mutex_lock (&global_mutex); + + /* Test again, since e.g. get_file_handle_for_path() might have + * snatched the global mutex and revived the file handle between + * g_atomic_int_dec_and_test() and us obtaining the lock. */ + + if (g_atomic_int_get (&file_handle->refcount) == 0) + g_hash_table_remove (global_fh_table, file_handle->path); + + g_static_mutex_unlock (&global_mutex); + } +} + +static void file_handle_close_stream (FileHandle *file_handle) { debug_print ("file_handle_close_stream\n"); @@ -220,11 +250,13 @@ file_handle_close_stream (FileHandle *fi } } +/* Called on hash table removal */ static void file_handle_free (FileHandle *file_handle) { file_handle_close_stream (file_handle); g_mutex_free (file_handle->mutex); + g_free (file_handle->path); g_free (file_handle); } @@ -234,7 +266,11 @@ get_file_handle_for_path (const gchar *p FileHandle *fh; g_static_mutex_lock (&global_mutex); + fh = g_hash_table_lookup (global_fh_table, path); + if (fh) + file_handle_ref (fh); + g_static_mutex_unlock (&global_mutex); return fh; @@ -245,15 +281,21 @@ get_or_create_file_handle_for_path (cons { FileHandle *fh; - fh = get_file_handle_for_path (path); - if (!fh) - { - fh = file_handle_new (); + g_static_mutex_lock (&global_mutex); - g_static_mutex_lock (&global_mutex); - g_hash_table_insert (global_fh_table, g_strdup (path), fh); - g_static_mutex_unlock (&global_mutex); + fh = g_hash_table_lookup (global_fh_table, path); + + if (fh) + { + file_handle_ref (fh); } + else + { + fh = file_handle_new (path); + g_hash_table_insert (global_fh_table, fh->path, fh); + } + + g_static_mutex_unlock (&global_mutex); return fh; } @@ -271,30 +313,15 @@ reindex_file_handle_for_path (const gcha (gpointer *) &fh)) goto out; - g_free (old_path_internal); - g_hash_table_insert (global_fh_table, g_strdup (new_path), fh); + g_free (fh->path); + fh->path = g_strdup (new_path); + g_hash_table_steal (global_fh_table, old_path); + g_hash_table_insert (global_fh_table, fh->path, fh); out: g_static_mutex_unlock (&global_mutex); } -static gboolean -free_file_handle_for_path (const gchar *path) -{ - FileHandle *fh; - - fh = get_file_handle_for_path (path); - if (fh) - { - g_static_mutex_lock (&global_mutex); - g_hash_table_remove (global_fh_table, path); - g_static_mutex_unlock (&global_mutex); - return TRUE; - } - - return FALSE; -} - static MountRecord * mount_record_new (GMount *mount) { @@ -795,7 +822,10 @@ vfs_getattr (const gchar *path, struct s } if (fh) - g_mutex_unlock (fh->mutex); + { + g_mutex_unlock (fh->mutex); + file_handle_unref (fh); + } debug_print ("vfs_getattr: -> %s\n", strerror (-result)); @@ -933,6 +963,8 @@ vfs_open (const gchar *path, struct fuse result = setup_output_stream (file, fh); else result = setup_input_stream (file, fh); + + /* The added reference to the file handle is released in vfs_release() */ } else if (file_type == G_FILE_TYPE_DIRECTORY) { @@ -1019,6 +1051,8 @@ vfs_create (const gchar *path, mode_t mo fh->stream = file_output_stream; fh->op = FILE_OP_WRITE; + + /* The added reference to the file handle is released in vfs_release() */ } else { @@ -1047,7 +1081,7 @@ vfs_release (const gchar *path, struct f debug_print ("vfs_release: %s\n", path); if (fh) - free_file_handle_for_path (path); + file_handle_unref (fh); return 0; } @@ -1479,6 +1513,7 @@ vfs_rename (const gchar *old_path, const if (fh) { g_mutex_unlock (fh->mutex); + file_handle_unref (fh); } if (result == -EISDIR) @@ -1530,6 +1565,7 @@ vfs_unlink (const gchar *path) if (fh) { g_mutex_unlock (fh->mutex); + file_handle_unref (fh); } if (error) @@ -1748,7 +1784,10 @@ vfs_truncate (const gchar *path, off_t s } if (fh) - g_mutex_unlock (fh->mutex); + { + g_mutex_unlock (fh->mutex); + file_handle_unref (fh); + } g_object_unref (file); } @@ -1998,6 +2037,9 @@ subthread_main (gpointer data) g_object_unref (volume_monitor); volume_monitor = NULL; + /* Tell the main thread to unmount. Using kill() is necessary according to FUSE maintainers. */ + kill (getpid (), SIGHUP); + return NULL; } @@ -2025,9 +2067,16 @@ dbus_filter_func (DBusConnection *connec *new_owner == 0) { /* The daemon died, unmount */ - kill (getpid(), SIGHUP); + g_main_loop_quit (subthread_main_loop); } } + else if (dbus_message_is_signal (message, + DBUS_INTERFACE_LOCAL, + "Disconnected")) + { + /* Session bus died, unmount */ + g_main_loop_quit (subthread_main_loop); + } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } @@ -2046,7 +2094,7 @@ vfs_init (struct fuse_conn_info *conn) mount_list_mutex = g_mutex_new (); global_fh_table = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, (GDestroyNotify) file_handle_free); + NULL, (GDestroyNotify) file_handle_free); dbus_error_init (&error); @@ -2059,6 +2107,8 @@ vfs_init (struct fuse_conn_info *conn) return NULL; } + dbus_connection_set_exit_on_disconnect (dbus_conn, FALSE); + _g_dbus_connection_integrate_with_main (dbus_conn); dbus_bus_add_match (dbus_conn,