[evolution-data-server] Add e_file_recursive_delete().



commit 7956a7063a453feeb0df5f7a03b44721079d7abe
Author: Matthew Barnes <mbarnes redhat com>
Date:   Sat Apr 7 13:37:20 2012 -0400

    Add e_file_recursive_delete().
    
    Equivalent to "rm -r FILE".  Use with caution.

 .../libedataserver/libedataserver-sections.txt     |    3 +
 libedataserver/e-data-server-util.c                |  175 ++++++++++++++++++++
 libedataserver/e-data-server-util.h                |   14 ++-
 3 files changed, 191 insertions(+), 1 deletions(-)
---
diff --git a/docs/reference/libedataserver/libedataserver-sections.txt b/docs/reference/libedataserver/libedataserver-sections.txt
index 824007b..8ad7f47 100644
--- a/docs/reference/libedataserver/libedataserver-sections.txt
+++ b/docs/reference/libedataserver/libedataserver-sections.txt
@@ -551,6 +551,9 @@ e_util_copy_string_slist
 e_util_copy_object_slist
 e_util_free_string_slist
 e_util_free_object_slist
+e_file_recursive_delete_sync
+e_file_recursive_delete
+e_file_recursive_delete_finish
 e_binding_transform_enum_value_to_nick
 e_binding_transform_enum_nick_to_value
 e_util_get_prefix
diff --git a/libedataserver/e-data-server-util.c b/libedataserver/e-data-server-util.c
index a608fbd..91f196c 100644
--- a/libedataserver/e-data-server-util.c
+++ b/libedataserver/e-data-server-util.c
@@ -966,6 +966,181 @@ e_util_free_nullable_object_slist (GSList *objects)
 	g_slist_free (objects);
 }
 
+/* Helper for e_file_recursive_delete() */
+static void
+file_recursive_delete_thread (GSimpleAsyncResult *simple,
+                              GObject *object,
+                              GCancellable *cancellable)
+{
+	GError *error = NULL;
+
+	e_file_recursive_delete_sync (G_FILE (object), cancellable, &error);
+
+	if (error != NULL)
+		g_simple_async_result_take_error (simple, error);
+}
+
+/**
+ * e_file_recursive_delete_sync:
+ * @file: a #GFile to delete
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Deletes @file.  If @file is a directory, its contents are deleted
+ * recursively before @file itself is deleted.  The recursive delete
+ * operation will stop on the first error.
+ *
+ * If @cancellable is not %NULL, then the operation can be cancelled
+ * by triggering the cancellable object from another thread.  If the
+ * operation was cancelled, the error #G_IO_ERROR_CANCELLED will be
+ * returned.
+ *
+ * Returns: %TRUE if the file was deleted, %FALSE otherwise
+ *
+ * Since: 3.6
+ **/
+gboolean
+e_file_recursive_delete_sync (GFile *file,
+                              GCancellable *cancellable,
+                              GError **error)
+{
+	GFileEnumerator *file_enumerator;
+	GFileInfo *file_info;
+	GFileType file_type;
+	gboolean success = TRUE;
+	GError *local_error = NULL;
+
+	g_return_val_if_fail (G_IS_FILE (file), FALSE);
+
+	file_type = g_file_query_file_type (
+		file, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, cancellable);
+
+	/* If this is not a directory, delete like normal. */
+	if (file_type != G_FILE_TYPE_DIRECTORY)
+		return g_file_delete (file, cancellable, error);
+
+	/* Note, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS is critical here
+	 * so we only delete files inside the directory being deleted. */
+	file_enumerator = g_file_enumerate_children (
+		file, G_FILE_ATTRIBUTE_STANDARD_NAME,
+		G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+		cancellable, error);
+
+	if (file_enumerator == NULL)
+		return FALSE;
+
+	file_info = g_file_enumerator_next_file (
+		file_enumerator, cancellable, &local_error);
+
+	while (file_info != NULL) {
+		GFile *child;
+		const gchar *name;
+
+		name = g_file_info_get_name (file_info);
+
+		/* Here's the recursive part. */
+		child = g_file_get_child (file, name);
+		success = e_file_recursive_delete_sync (
+			child, cancellable, error);
+		g_object_unref (child);
+
+		g_object_unref (file_info);
+
+		if (!success)
+			break;
+
+		file_info = g_file_enumerator_next_file (
+			file_enumerator, cancellable, &local_error);
+	}
+
+	if (local_error != NULL) {
+		g_propagate_error (error, local_error);
+		success = FALSE;
+	}
+
+	g_object_unref (file_enumerator);
+
+	if (!success)
+		return FALSE;
+
+	/* The directory should be empty now. */
+	return g_file_delete (file, cancellable, error);
+}
+
+/**
+ * e_file_recursive_delete:
+ * @file: a #GFile to delete
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously deletes @file.  If @file is a directory, its contents
+ * are deleted recursively before @file itself is deleted.  The recursive
+ * delete operation will stop on the first error.
+ *
+ * If @cancellable is not %NULL, then the operation can be cancelled
+ * by triggering the cancellable object before the operation finishes.
+ *
+ * When the operation is finished, @callback will be called.  You can then
+ * call e_file_recursive_delete_finish() to get the result of the operation.
+ *
+ * Since: 3.6
+ **/
+void
+e_file_recursive_delete (GFile *file,
+                         gint io_priority,
+                         GCancellable *cancellable,
+                         GAsyncReadyCallback callback,
+                         gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_if_fail (G_IS_FILE (file));
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (file), callback, user_data,
+		e_file_recursive_delete);
+
+	g_simple_async_result_run_in_thread (
+		simple, file_recursive_delete_thread,
+		io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+/**
+ * e_file_recursive_delete_finish:
+ * @file: a #GFile to delete
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with e_file_recursive_delete().
+ *
+ * If the operation was cancelled, the error #G_IO_ERROR_CANCELLED will be
+ * returned.
+ *
+ * Returns: %TRUE if the file was deleted, %FALSE otherwise
+ *
+ * Since: 3.6
+ **/
+gboolean
+e_file_recursive_delete_finish (GFile *file,
+                                GAsyncResult *result,
+                                GError **error)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (file), e_file_recursive_delete), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
+}
+
 /**
  * e_binding_transform_enum_value_to_nick:
  * @binding: a #GBinding
diff --git a/libedataserver/e-data-server-util.h b/libedataserver/e-data-server-util.h
index b68c460..a137c6c 100644
--- a/libedataserver/e-data-server-util.h
+++ b/libedataserver/e-data-server-util.h
@@ -23,7 +23,7 @@
 #define E_DATA_SERVER_UTIL_H
 
 #include <sys/types.h>
-#include <glib-object.h>
+#include <gio/gio.h>
 
 G_BEGIN_DECLS
 
@@ -71,6 +71,18 @@ void		e_util_free_string_slist	(GSList *strings);
 void		e_util_free_object_slist	(GSList *objects);
 void		e_util_free_nullable_object_slist	(GSList *objects);
 
+gboolean	e_file_recursive_delete_sync	(GFile *file,
+						 GCancellable *cancellable,
+						 GError **error);
+void		e_file_recursive_delete		(GFile *file,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean	e_file_recursive_delete_finish	(GFile *file,
+						 GAsyncResult *result,
+						 GError **error);
+
 /* Useful GBinding transform functions */
 gboolean	e_binding_transform_enum_value_to_nick
 						(GBinding *binding,



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]