From 14a1c20177eab4d584b29cbd6fe5933f4b2af4de Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Sat, 28 Jul 2012 09:30:22 -0400 Subject: [PATCH] GFile: Add g_file_delete_async() This looks like it was stubbed out but not implemented; the vtable entry dates to commit 3781343738de4abddf56982325a77bd70a98cd26 which is just alex's initial merge of gio into glib. I was working on some code that wants an asynchronous rm -rf equivalent, and so yeah, this is desirable. https://bugzilla.gnome.org/show_bug.cgi?id=680760 --- docs/reference/gio/gio-sections.txt | 2 + gio/gfile.c | 118 ++++++++++++++++++++++++++++ gio/gfile.h | 27 ++++++- gio/gio.symbols | 2 + gio/tests/file.c | 43 ++++++++++ 5 files changed, 188 insertions(+), 4 deletions(-) diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt index e709e83d5..991cc3262 100644 --- a/docs/reference/gio/gio-sections.txt +++ b/docs/reference/gio/gio-sections.txt @@ -127,6 +127,8 @@ g_file_set_display_name g_file_set_display_name_async g_file_set_display_name_finish g_file_delete +g_file_delete_async +g_file_delete_finish g_file_trash g_file_copy g_file_copy_async diff --git a/gio/gfile.c b/gio/gfile.c index abc7e27e1..b76939f9f 100644 --- a/gio/gfile.c +++ b/gio/gfile.c @@ -196,6 +196,14 @@ static void g_file_real_replace_async (GFile static GFileOutputStream *g_file_real_replace_finish (GFile *file, GAsyncResult *res, GError **error); +static void g_file_real_delete_async (GFile *file, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +static gboolean g_file_real_delete_finish (GFile *file, + GAsyncResult *res, + GError **error); static void g_file_real_open_readwrite_async (GFile *file, int io_priority, GCancellable *cancellable, @@ -294,6 +302,8 @@ g_file_default_init (GFileIface *iface) iface->create_finish = g_file_real_create_finish; iface->replace_async = g_file_real_replace_async; iface->replace_finish = g_file_real_replace_finish; + iface->delete_file_async = g_file_real_delete_async; + iface->delete_file_finish = g_file_real_delete_finish; iface->open_readwrite_async = g_file_real_open_readwrite_async; iface->open_readwrite_finish = g_file_real_open_readwrite_finish; iface->create_readwrite_async = g_file_real_create_readwrite_async; @@ -3507,6 +3517,69 @@ g_file_delete (GFile *file, return (* iface->delete_file) (file, cancellable, error); } +/** + * g_file_delete_async: + * @file: input #GFile. + * @io_priority: the I/O priority + * of the request + * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore. + * @callback: a #GAsyncReadyCallback to call when the request is satisfied + * @user_data: the data to pass to callback function + * + * Asynchronously delete a file. If the @file is a directory, it will + * only be deleted if it is empty. + * + * Virtual: delete_file_async + * Since: 2.34 + **/ +void +g_file_delete_async (GFile *file, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GFileIface *iface; + + g_return_if_fail (G_IS_FILE (file)); + + iface = G_FILE_GET_IFACE (file); + (* iface->delete_file_async) (file, + io_priority, + cancellable, + callback, + user_data); +} + +/** + * g_file_delete_finish: + * @file: input #GFile. + * @res: a #GAsyncResult. + * @error: a #GError, or %NULL + * + * Finishes deleting a file started with + * g_file_delete_async(). + * + * Virtual: delete_file_finish + * Since: 2.34 + **/ +gboolean +g_file_delete_finish (GFile *file, + GAsyncResult *result, + GError **error) +{ + GFileIface *iface; + + g_return_val_if_fail (G_IS_FILE (file), FALSE); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); + + if (g_async_result_legacy_propagate_error (result, error)) + return FALSE; + + iface = G_FILE_GET_IFACE (file); + return (* iface->delete_file_finish) (file, result, error); +} + /** * g_file_trash: * @file: #GFile to send to trash. @@ -5256,6 +5329,51 @@ g_file_real_replace_finish (GFile *file, return NULL; } +static void +delete_async_thread (GSimpleAsyncResult *res, + GObject *object, + GCancellable *cancellable) +{ + GFileIface *iface; + GError *error = NULL; + + iface = G_FILE_GET_IFACE (object); + + if (!iface->delete_file (G_FILE (object), + cancellable, + &error)) + g_simple_async_result_take_error (res, error); +} + +static void +g_file_real_delete_async (GFile *file, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *res; + + res = g_simple_async_result_new (G_OBJECT (file), callback, user_data, g_file_real_delete_async); + g_simple_async_result_run_in_thread (res, delete_async_thread, io_priority, cancellable); + g_object_unref (res); +} + +static gboolean +g_file_real_delete_finish (GFile *file, + GAsyncResult *res, + GError **error) +{ + GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res); + + g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_file_real_delete_async); + + if (g_simple_async_result_propagate_error (simple, error)) + return FALSE; + + return TRUE; +} + static void open_readwrite_async_thread (GSimpleAsyncResult *res, GObject *object, diff --git a/gio/gfile.h b/gio/gfile.h index f784c5de4..1a724db6e 100644 --- a/gio/gfile.h +++ b/gio/gfile.h @@ -105,8 +105,8 @@ typedef struct _GFileIface GFileIface; * @replace_async: Asynchronously replaces the contents of a file. * @replace_finish: Finishes asynchronously replacing a file. * @delete_file: Deletes a file. - * @_delete_file_async: Asynchronously deletes a file. - * @_delete_file_finish: Finishes an asynchronous delete. + * @delete_file_async: Asynchronously deletes a file. + * @delete_file_finish: Finishes an asynchronous delete. * @trash: Sends a #GFile to the Trash location. * @_trash_async: Asynchronously sends a #GFile to the Trash location. * @_trash_finish: Finishes an asynchronous file trashing operation. @@ -353,8 +353,14 @@ struct _GFileIface gboolean (* delete_file) (GFile *file, GCancellable *cancellable, GError **error); - void (* _delete_file_async) (void); - void (* _delete_file_finish) (void); + void (* delete_file_async) (GFile *file, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (* delete_file_finish) (GFile *file, + GAsyncResult *result, + GError **error); gboolean (* trash) (GFile *file, GCancellable *cancellable, @@ -751,6 +757,19 @@ GFile * g_file_set_display_name_finish (GFile gboolean g_file_delete (GFile *file, GCancellable *cancellable, GError **error); + +GLIB_AVAILABLE_IN_2_34 +void g_file_delete_async (GFile *file, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +GLIB_AVAILABLE_IN_2_34 +gboolean g_file_delete_finish (GFile *file, + GAsyncResult *result, + GError **error); + gboolean g_file_trash (GFile *file, GCancellable *cancellable, GError **error); diff --git a/gio/gio.symbols b/gio/gio.symbols index 6db9bbd2d..a60e1e9b0 100644 --- a/gio/gio.symbols +++ b/gio/gio.symbols @@ -303,6 +303,8 @@ g_file_set_display_name g_file_set_display_name_async g_file_set_display_name_finish g_file_delete +g_file_delete_async +g_file_delete_finish g_file_trash g_file_copy g_file_copy_async diff --git a/gio/tests/file.c b/gio/tests/file.c index c7f840be6..5fed88b56 100644 --- a/gio/tests/file.c +++ b/gio/tests/file.c @@ -592,6 +592,48 @@ test_replace_load (void) free (path); } +static void +on_file_deleted (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + GError *local_error = NULL; + GMainLoop *loop = user_data; + + (void) g_file_delete_finish ((GFile*)object, result, &local_error); + g_assert_no_error (local_error); + + g_main_loop_quit (loop); +} + +static void +test_async_delete (void) +{ + GFile *file; + GFileIOStream *iostream; + GError *local_error = NULL; + GError **error = &local_error; + GMainLoop *loop; + + file = g_file_new_tmp ("g_file_delete_XXXXXX", + &iostream, error); + g_assert_no_error (local_error); + g_object_unref (iostream); + + g_assert (g_file_query_exists (file, NULL)); + + loop = g_main_loop_new (NULL, TRUE); + + g_file_delete_async (file, G_PRIORITY_DEFAULT, NULL, on_file_deleted, loop); + + g_main_loop_run (loop); + + g_assert (!g_file_query_exists (file, NULL)); + + g_main_loop_unref (loop); + g_object_unref (file); +} + int main (int argc, char *argv[]) { @@ -609,6 +651,7 @@ main (int argc, char *argv[]) g_test_add_data_func ("/file/async-create-delete/25", GINT_TO_POINTER (25), test_create_delete); g_test_add_data_func ("/file/async-create-delete/4096", GINT_TO_POINTER (4096), test_create_delete); g_test_add_func ("/file/replace-load", test_replace_load); + g_test_add_func ("/file/async-delete", test_async_delete); return g_test_run (); }