[evolution-data-server/account-mgmt: 41/42] Add 'cache-reaper' module.
- From: Matthew Barnes <mbarnes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server/account-mgmt: 41/42] Add 'cache-reaper' module.
- Date: Tue, 24 Apr 2012 23:13:03 +0000 (UTC)
commit 33ec3b7398e7ab6a397eb90cf02e89c64b3e70bd
Author: Matthew Barnes <mbarnes redhat com>
Date: Fri Apr 6 15:21:37 2012 -0400
Add 'cache-reaper' module.
configure.ac | 1 +
modules/Makefile.am | 1 +
modules/cache-reaper/Makefile.am | 30 ++
modules/cache-reaper/e-cache-reaper-utils.c | 196 ++++++++++
modules/cache-reaper/e-cache-reaper-utils.h | 41 +++
modules/cache-reaper/module-cache-reaper.c | 513 +++++++++++++++++++++++++++
6 files changed, 782 insertions(+), 0 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 111b094..425482e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1651,6 +1651,7 @@ libedataserver/libedataserver.pc
libedataserverui/Makefile
libedataserverui/libedataserverui.pc
modules/Makefile
+modules/cache-reaper/Makefile
modules/google-backend/Makefile
modules/online-accounts/Makefile
modules/yahoo-backend/Makefile
diff --git a/modules/Makefile.am b/modules/Makefile.am
index 47a2e70..8023faf 100644
--- a/modules/Makefile.am
+++ b/modules/Makefile.am
@@ -5,6 +5,7 @@ ONLINE_ACCOUNTS_DIR = online-accounts
endif
SUBDIRS = \
+ cache-reaper \
google-backend \
yahoo-backend \
$(ONLINE_ACCOUNTS_DIR) \
diff --git a/modules/cache-reaper/Makefile.am b/modules/cache-reaper/Makefile.am
new file mode 100644
index 0000000..510a4a6
--- /dev/null
+++ b/modules/cache-reaper/Makefile.am
@@ -0,0 +1,30 @@
+NULL =
+
+module_LTLIBRARIES = module-cache-reaper.la
+
+module_cache_reaper_la_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ -I$(top_srcdir) \
+ -DG_LOG_DOMAIN=\"module-cache-reaper\" \
+ $(E_BACKEND_CFLAGS) \
+ $(E_DATA_SERVER_CFLAGS) \
+ $(NULL)
+
+module_cache_reaper_la_SOURCES = \
+ module-cache-reaper.c \
+ e-cache-reaper-utils.c \
+ e-cache-reaper-utils.h \
+ $(NULL)
+
+module_cache_reaper_la_LIBADD = \
+ $(top_builddir)/libebackend/libebackend-1.2.la \
+ $(top_builddir)/libedataserver/libedataserver-1.2.la \
+ $(E_BACKEND_LIBS) \
+ $(E_DATA_SERVER_LIBS) \
+ $(NULL)
+
+module_cache_reaper_la_LDFLAGS = \
+ -module -avoid-version $(NO_UNDEFINED) \
+ $(NULL)
+
+-include $(top_srcdir)/git.mk
diff --git a/modules/cache-reaper/e-cache-reaper-utils.c b/modules/cache-reaper/e-cache-reaper-utils.c
new file mode 100644
index 0000000..4ba57c4
--- /dev/null
+++ b/modules/cache-reaper/e-cache-reaper-utils.c
@@ -0,0 +1,196 @@
+/*
+ * e-cache-reaper-utils.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-cache-reaper-utils.h"
+
+#include <libedataserver/e-data-server-util.h>
+
+#define REAPING_DIRECTORY_NAME ".reaping"
+
+#define MINIMUM_DAYS_OLD_TO_REAP 5
+
+/* Helper for e_reap_trash_directory() */
+static void
+reap_trash_directory_thread (GSimpleAsyncResult *simple,
+ GObject *object,
+ GCancellable *cancellable)
+{
+ GError *error = NULL;
+
+ e_reap_trash_directory_sync (G_FILE (object), cancellable, &error);
+
+ if (error != NULL)
+ g_simple_async_result_take_error (simple, error);
+}
+
+gboolean
+e_reap_trash_directory_sync (GFile *trash_directory,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GFileEnumerator *file_enumerator;
+ GQueue directories = G_QUEUE_INIT;
+ GFile *reaping_directory;
+ GFileInfo *file_info;
+ const gchar *attributes;
+ gboolean success = TRUE;
+ GError *local_error = NULL;
+
+ g_return_val_if_fail (G_IS_FILE (trash_directory), FALSE);
+
+ reaping_directory = g_file_get_child (
+ trash_directory, REAPING_DIRECTORY_NAME);
+
+ attributes =
+ G_FILE_ATTRIBUTE_STANDARD_NAME ","
+ G_FILE_ATTRIBUTE_STANDARD_TYPE ","
+ G_FILE_ATTRIBUTE_TIME_MODIFIED;
+
+ file_enumerator = g_file_enumerate_children (
+ trash_directory, attributes,
+ 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) {
+ GFileType file_type;
+ GTimeVal mtime;
+ GDate *date_now;
+ GDate *date_mtime;
+ const gchar *name;
+ gboolean reap_it;
+ gint days_old;
+
+ name = g_file_info_get_name (file_info);
+ file_type = g_file_info_get_file_type (file_info);
+ g_file_info_get_modification_time (file_info, &mtime);
+
+ /* Calculate how many days ago the file was modified. */
+ date_now = g_date_new ();
+ g_date_set_time_t (date_now, time (NULL));
+ date_mtime = g_date_new ();
+ g_date_set_time_val (date_mtime, &mtime);
+ days_old = g_date_days_between (date_mtime, date_now);
+ g_date_free (date_mtime);
+ g_date_free (date_now);
+
+ reap_it =
+ (file_type == G_FILE_TYPE_DIRECTORY) &&
+ (days_old >= MINIMUM_DAYS_OLD_TO_REAP);
+
+ if (reap_it) {
+ GFile *child;
+
+ child = g_file_get_child (trash_directory, name);
+
+ /* If we find an unfinished reaping directory, put
+ * it on the head of the queue so we reap it first. */
+ if (g_file_equal (child, reaping_directory))
+ g_queue_push_head (&directories, child);
+ else
+ g_queue_push_tail (&directories, child);
+ }
+
+ g_object_unref (file_info);
+
+ 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);
+
+ /* Now delete the directories we've queued up. */
+ while (success && !g_queue_is_empty (&directories)) {
+ GFile *directory;
+
+ directory = g_queue_pop_head (&directories);
+
+ /* First we rename the directory to prevent it
+ * from being recovered while being deleted. */
+ if (!g_file_equal (directory, reaping_directory))
+ success = g_file_move (
+ directory, reaping_directory,
+ G_FILE_COPY_NONE, cancellable,
+ NULL, NULL, error);
+
+ if (success)
+ success = e_file_recursive_delete_sync (
+ reaping_directory, cancellable, error);
+
+ g_object_unref (directory);
+ }
+
+ /* Flush the queue in case we aborted on an error. */
+ while (!g_queue_is_empty (&directories))
+ g_object_unref (g_queue_pop_head (&directories));
+
+ g_object_unref (reaping_directory);
+
+ return success;
+}
+
+void
+e_reap_trash_directory (GFile *trash_directory,
+ gint io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_if_fail (G_IS_FILE (trash_directory));
+
+ simple = g_simple_async_result_new (
+ G_OBJECT (trash_directory), callback,
+ user_data, e_reap_trash_directory);
+
+ g_simple_async_result_run_in_thread (
+ simple, reap_trash_directory_thread,
+ io_priority, cancellable);
+
+ g_object_unref (simple);
+}
+
+gboolean
+e_reap_trash_directory_finish (GFile *trash_directory,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (
+ g_simple_async_result_is_valid (
+ result, G_OBJECT (trash_directory),
+ e_reap_trash_directory), FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+
+ /* Assume success unless a GError is set. */
+ return !g_simple_async_result_propagate_error (simple, error);
+}
+
diff --git a/modules/cache-reaper/e-cache-reaper-utils.h b/modules/cache-reaper/e-cache-reaper-utils.h
new file mode 100644
index 0000000..0b92801
--- /dev/null
+++ b/modules/cache-reaper/e-cache-reaper-utils.h
@@ -0,0 +1,41 @@
+/*
+ * e-cache-reaper-utils.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_CACHE_REAPER_UTILS_H
+#define E_CACHE_REAPER_UTILS_H
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+gboolean e_reap_trash_directory_sync (GFile *trash_directory,
+ GCancellable *cancellable,
+ GError **error);
+void e_reap_trash_directory (GFile *trash_directory,
+ gint io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean e_reap_trash_directory_finish (GFile *trash_directory,
+ GAsyncResult *result,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* E_CACHE_REAPER_UTILS_H */
+
diff --git a/modules/cache-reaper/module-cache-reaper.c b/modules/cache-reaper/module-cache-reaper.c
new file mode 100644
index 0000000..39c4142
--- /dev/null
+++ b/modules/cache-reaper/module-cache-reaper.c
@@ -0,0 +1,513 @@
+/*
+ * module-cache-reaper.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include <errno.h>
+#include <time.h>
+#include <glib/gstdio.h>
+
+#include <libedataserver/e-data-server-util.h>
+
+#include <libebackend/e-extension.h>
+#include <libebackend/e-source-registry-server.h>
+
+#include "e-cache-reaper-utils.h"
+
+/* Standard GObject macros */
+#define E_TYPE_CACHE_REAPER \
+ (e_cache_reaper_get_type ())
+#define E_CACHE_REAPER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_CACHE_REAPER, ECacheReaper))
+
+/* Where abandoned cache directories go to die. */
+#define TRASH_DIRECTORY_NAME "trash"
+
+/* XXX These intervals are rather arbitrary and prone to bikeshedding.
+ * It's just what I decided on. On startup we wait an hour to reap
+ * abandoned cache directories, and thereafter repeat every 24 hours. */
+#define INITIAL_INTERVAL_SECONDS ( 1 * (60 * 60))
+#define REGULAR_INTERVAL_SECONDS (24 * (60 * 60))
+
+typedef struct _ECacheReaper ECacheReaper;
+typedef struct _ECacheReaperClass ECacheReaperClass;
+
+struct _ECacheReaper {
+ EExtension parent;
+
+ guint n_directories;
+ GFile **cache_directories;
+ GFile **trash_directories;
+
+ guint reaping_timeout_id;
+};
+
+struct _ECacheReaperClass {
+ EExtensionClass parent_class;
+};
+
+/* Module Entry Points */
+void e_module_load (GTypeModule *type_module);
+void e_module_unload (GTypeModule *type_module);
+
+/* Forward Declarations */
+GType e_cache_reaper_get_type (void);
+
+G_DEFINE_DYNAMIC_TYPE (
+ ECacheReaper,
+ e_cache_reaper,
+ E_TYPE_EXTENSION)
+
+static ESourceRegistryServer *
+cache_reaper_get_server (ECacheReaper *extension)
+{
+ EExtensible *extensible;
+
+ extensible = e_extension_get_extensible (E_EXTENSION (extension));
+
+ return E_SOURCE_REGISTRY_SERVER (extensible);
+}
+
+static void
+cache_reaper_trash_directory_reaped (GObject *source_object,
+ GAsyncResult *result,
+ gpointer unused)
+{
+ GFile *trash_directory;
+ GError *error = NULL;
+
+ trash_directory = G_FILE (source_object);
+
+ e_reap_trash_directory_finish (trash_directory, result, &error);
+
+ /* Ignore cancellations. */
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ /* do nothing */
+
+ } else if (error != NULL) {
+ gchar *path;
+
+ path = g_file_get_path (trash_directory);
+ g_warning ("Failed to reap '%s': %s", path, error->message);
+ g_free (path);
+ }
+
+ g_clear_error (&error);
+}
+
+static gboolean
+cache_reaper_reap_trash_directories (gpointer user_data)
+{
+ ECacheReaper *extension = E_CACHE_REAPER (user_data);
+ guint ii;
+
+ g_message ("Reaping abandoned cache directories");
+
+ for (ii = 0; ii < extension->n_directories; ii++)
+ e_reap_trash_directory (
+ extension->trash_directories[ii],
+ G_PRIORITY_LOW, NULL,
+ cache_reaper_trash_directory_reaped,
+ NULL);
+
+ /* Always explicitly reschedule since the initial
+ * interval is different than the regular interval. */
+ extension->reaping_timeout_id =
+ g_timeout_add_seconds (
+ REGULAR_INTERVAL_SECONDS,
+ cache_reaper_reap_trash_directories,
+ extension);
+
+ return FALSE;
+}
+
+static void
+cache_reaper_move_directory (GFile *source_directory,
+ GFile *target_directory)
+{
+ GFileType file_type;
+ GError *error = NULL;
+
+ /* Make sure the source directory is really a directory. */
+
+ file_type = g_file_query_file_type (
+ source_directory,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL);
+
+ if (file_type == G_FILE_TYPE_DIRECTORY) {
+ g_file_move (
+ source_directory,
+ target_directory,
+ G_FILE_COPY_NOFOLLOW_SYMLINKS,
+ NULL, NULL, NULL, &error);
+
+ /* Update the target directory's modification time.
+ * This step is not critical, do not set the GError. */
+ if (error == NULL) {
+ time_t now = time (NULL);
+
+ g_file_set_attribute (
+ target_directory,
+ G_FILE_ATTRIBUTE_TIME_MODIFIED,
+ G_FILE_ATTRIBUTE_TYPE_UINT64,
+ &now, G_FILE_QUERY_INFO_NONE,
+ NULL, NULL);
+ }
+ }
+
+ if (error != NULL) {
+ gchar *path;
+
+ path = g_file_get_path (source_directory);
+ g_warning ("Failed to move '%s': %s", path, error->message);
+ g_free (path);
+
+ g_error_free (error);
+ }
+}
+
+static void
+cache_reaper_scan_cache_directory (ECacheReaper *extension,
+ GFile *cache_directory,
+ GFile *trash_directory)
+{
+ GFileEnumerator *file_enumerator;
+ ESourceRegistryServer *server;
+ GFileInfo *file_info;
+ GError *error = NULL;
+
+ server = cache_reaper_get_server (extension);
+
+ file_enumerator = g_file_enumerate_children (
+ cache_directory,
+ G_FILE_ATTRIBUTE_STANDARD_NAME,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ NULL, &error);
+
+ if (error != NULL) {
+ g_warn_if_fail (file_enumerator == NULL);
+ goto exit;
+ }
+
+ g_return_if_fail (G_IS_FILE_ENUMERATOR (file_enumerator));
+
+ file_info = g_file_enumerator_next_file (
+ file_enumerator, NULL, &error);
+
+ while (file_info != NULL) {
+ ESource *source;
+ const gchar *name;
+
+ name = g_file_info_get_name (file_info);
+
+ /* Skip the trash directory, obviously. */
+ if (g_strcmp0 (name, TRASH_DIRECTORY_NAME) == 0)
+ goto next;
+
+ source = e_source_registry_server_ref_source (server, name);
+
+ if (source == NULL) {
+ GFile *source_directory;
+ GFile *target_directory;
+
+ source_directory = g_file_get_child (
+ cache_directory, name);
+ target_directory = g_file_get_child (
+ trash_directory, name);
+
+ cache_reaper_move_directory (
+ source_directory, target_directory);
+
+ g_object_unref (source_directory);
+ g_object_unref (target_directory);
+ } else {
+ g_object_unref (source);
+ }
+
+next:
+ g_object_unref (file_info);
+
+ file_info = g_file_enumerator_next_file (
+ file_enumerator, NULL, &error);
+ }
+
+ g_object_unref (file_enumerator);
+
+exit:
+ if (error != NULL) {
+ gchar *path;
+
+ path = g_file_get_path (cache_directory);
+ g_warning ("Failed to scan '%s': %s", path, error->message);
+ g_free (path);
+
+ g_error_free (error);
+ }
+}
+
+static void
+cache_reaper_scan_cache_directories (ECacheReaper *extension)
+{
+ guint ii;
+
+ /* Scan the base cache directories for unregnized subdirectories.
+ * The subdirectories are named after data source UIDs, so compare
+ * their names to registered data sources and move any unrecognized
+ * subdirectories to the "trash" subdirectory to be reaped later. */
+
+ g_message ("Scanning cache directories");
+
+ for (ii = 0; ii < extension->n_directories; ii++)
+ cache_reaper_scan_cache_directory (
+ extension,
+ extension->cache_directories[ii],
+ extension->trash_directories[ii]);
+}
+
+static void
+cache_reaper_move_cache_to_trash (ECacheReaper *extension,
+ ESource *source,
+ GFile *cache_directory,
+ GFile *trash_directory)
+{
+ GFile *source_directory;
+ GFile *target_directory;
+ const gchar *uid;
+
+ uid = e_source_get_uid (source);
+
+ source_directory = g_file_get_child (cache_directory, uid);
+ target_directory = g_file_get_child (trash_directory, uid);
+
+ /* This is a no-op if the source directory does not exist. */
+ cache_reaper_move_directory (source_directory, target_directory);
+
+ g_object_unref (source_directory);
+ g_object_unref (target_directory);
+}
+
+static void
+cache_reaper_recover_cache_from_trash (ECacheReaper *extension,
+ ESource *source,
+ GFile *cache_directory,
+ GFile *trash_directory)
+{
+ GFile *source_directory;
+ GFile *target_directory;
+ const gchar *uid;
+
+ uid = e_source_get_uid (source);
+
+ source_directory = g_file_get_child (trash_directory, uid);
+ target_directory = g_file_get_child (cache_directory, uid);
+
+ /* This is a no-op if the source directory does not exist. */
+ cache_reaper_move_directory (source_directory, target_directory);
+
+ g_object_unref (source_directory);
+ g_object_unref (target_directory);
+}
+
+static void
+cache_reaper_files_loaded_cb (ESourceRegistryServer *server,
+ ECacheReaper *extension)
+{
+ cache_reaper_scan_cache_directories (extension);
+
+ /* Schedule the initial reaping. */
+ if (extension->reaping_timeout_id == 0)
+ extension->reaping_timeout_id =
+ g_timeout_add_seconds (
+ INITIAL_INTERVAL_SECONDS,
+ cache_reaper_reap_trash_directories,
+ extension);
+}
+
+static void
+cache_reaper_source_added_cb (ESourceRegistryServer *server,
+ ESource *source,
+ ECacheReaper *extension)
+{
+ guint ii;
+
+ /* The Cache Reaper is not too proud to dig through the
+ * trash on the off chance the newly-added source has a
+ * recoverable cache directory. */
+ for (ii = 0; ii < extension->n_directories; ii++)
+ cache_reaper_recover_cache_from_trash (
+ extension, source,
+ extension->cache_directories[ii],
+ extension->trash_directories[ii]);
+}
+
+static void
+cache_reaper_source_removed_cb (ESourceRegistryServer *server,
+ ESource *source,
+ ECacheReaper *extension)
+{
+ guint ii;
+
+ /* Stage the removed source's cache directory for
+ * reaping by moving it to the "trash" directory. */
+ for (ii = 0; ii < extension->n_directories; ii++)
+ cache_reaper_move_cache_to_trash (
+ extension, source,
+ extension->cache_directories[ii],
+ extension->trash_directories[ii]);
+}
+
+static void
+cache_reaper_finalize (GObject *object)
+{
+ ECacheReaper *extension;
+ guint ii;
+
+ extension = E_CACHE_REAPER (object);
+
+ for (ii = 0; ii < extension->n_directories; ii++) {
+ g_object_unref (extension->cache_directories[ii]);
+ g_object_unref (extension->trash_directories[ii]);
+ }
+
+ g_free (extension->cache_directories);
+ g_free (extension->trash_directories);
+
+ if (extension->reaping_timeout_id > 0)
+ g_source_remove (extension->reaping_timeout_id);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (e_cache_reaper_parent_class)->finalize (object);
+}
+
+static void
+cache_reaper_constructed (GObject *object)
+{
+ EExtension *extension;
+ EExtensible *extensible;
+
+ extension = E_EXTENSION (object);
+ extensible = e_extension_get_extensible (extension);
+
+ g_signal_connect (
+ extensible, "files-loaded",
+ G_CALLBACK (cache_reaper_files_loaded_cb), extension);
+
+ g_signal_connect (
+ extensible, "source-added",
+ G_CALLBACK (cache_reaper_source_added_cb), extension);
+
+ g_signal_connect (
+ extensible, "source-removed",
+ G_CALLBACK (cache_reaper_source_removed_cb), extension);
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (e_cache_reaper_parent_class)->constructed (object);
+}
+
+static void
+e_cache_reaper_class_init (ECacheReaperClass *class)
+{
+ GObjectClass *object_class;
+ EExtensionClass *extension_class;
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->finalize = cache_reaper_finalize;
+ object_class->constructed = cache_reaper_constructed;
+
+ extension_class = E_EXTENSION_CLASS (class);
+ extension_class->extensible_type = E_TYPE_SOURCE_REGISTRY_SERVER;
+}
+
+static void
+e_cache_reaper_class_finalize (ECacheReaperClass *class)
+{
+}
+
+static void
+e_cache_reaper_init (ECacheReaper *extension)
+{
+ GFile *base_directory;
+ const gchar *user_cache_dir;
+ guint n_directories, ii;
+
+ /* These are component names from which
+ * the cache directory arrays are built. */
+ const gchar *component_names[] = {
+ "addressbook",
+ "calendar",
+ "mail",
+ "memos",
+ "tasks"
+ };
+
+ n_directories = G_N_ELEMENTS (component_names);
+
+ extension->n_directories = n_directories;
+ extension->cache_directories = g_new0 (GFile *, n_directories);
+ extension->trash_directories = g_new0 (GFile *, n_directories);
+
+ user_cache_dir = e_get_user_cache_dir ();
+ base_directory = g_file_new_for_path (user_cache_dir);
+
+ for (ii = 0; ii < n_directories; ii++) {
+ GFile *cache_directory;
+ GFile *trash_directory;
+ GError *error = NULL;
+
+ cache_directory = g_file_get_child (
+ base_directory, component_names[ii]);
+ trash_directory = g_file_get_child (
+ cache_directory, TRASH_DIRECTORY_NAME);
+
+ /* Cache directory is a parent of the trash
+ * directory so this is sufficient for both. */
+ g_file_make_directory_with_parents (
+ trash_directory, NULL, &error);
+
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS))
+ g_clear_error (&error);
+
+ if (error != NULL) {
+ gchar *path;
+
+ path = g_file_get_path (trash_directory);
+ g_warning (
+ "Failed to make directory '%s': %s",
+ path, error->message);
+ g_free (path);
+
+ g_error_free (error);
+ }
+
+ extension->cache_directories[ii] = cache_directory;
+ extension->trash_directories[ii] = trash_directory;
+ }
+
+ g_object_unref (base_directory);
+}
+
+G_MODULE_EXPORT void
+e_module_load (GTypeModule *type_module)
+{
+ e_cache_reaper_register_type (type_module);
+}
+
+G_MODULE_EXPORT void
+e_module_unload (GTypeModule *type_module)
+{
+}
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]