/*
* e-cache-reaper-utils.c
*
* This library 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.
*
* This library 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 this library. If not, see .
*
*/
#include "e-cache-reaper-utils.h"
#include
#define REAPING_DIRECTORY_NAME ".reaping"
/* Helper for e_reap_trash_directory() */
static void
reap_trash_directory_thread (GSimpleAsyncResult *simple,
GObject *object,
GCancellable *cancellable)
{
gssize expiry_in_days;
GError *error = NULL;
expiry_in_days = g_simple_async_result_get_op_res_gssize (simple);
e_reap_trash_directory_sync (
G_FILE (object),
(gint) expiry_in_days,
cancellable, &error);
if (error != NULL)
g_simple_async_result_take_error (simple, error);
}
gboolean
e_reap_trash_directory_sync (GFile *trash_directory,
gint expiry_in_days,
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);
g_return_val_if_fail (expiry_in_days > 0, 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 >= expiry_in_days);
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 expiry_in_days,
gint io_priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GSimpleAsyncResult *simple;
g_return_if_fail (G_IS_FILE (trash_directory));
g_return_if_fail (expiry_in_days > 0);
simple = g_simple_async_result_new (
G_OBJECT (trash_directory), callback,
user_data, e_reap_trash_directory);
g_simple_async_result_set_check_cancellable (simple, cancellable);
g_simple_async_result_set_op_res_gssize (simple, expiry_in_days);
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);
}