From aa66a17e401d73cbe394ed7f99bf73350e9b938b Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Fri, 6 Nov 2009 13:33:55 -0500 Subject: Test drive EIOActivity with a simple asynchronous function. Rename e-fsutils to e-file-utils. This is where we'll add asynchronous functions for common file I/O operations with EActivity integration. Start with e_file_replace_contents_async() (and corresponding finish() function). This is a simple wrapper for g_file_replace_contents_async() which also returns an EActivity. It replaces e_write_file_uri(). Also redesign EIOActivity to -contain- a GAsyncResult rather than implement the interface for itself. This is easier for now but I may change my mind again when I figure out how to tie centralized error reporting into the EActivity framework. --- e-util/e-file-utils.c | 281 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 281 insertions(+) create mode 100644 e-util/e-file-utils.c (limited to 'e-util/e-file-utils.c') diff --git a/e-util/e-file-utils.c b/e-util/e-file-utils.c new file mode 100644 index 0000000000..f8adcc7a60 --- /dev/null +++ b/e-util/e-file-utils.c @@ -0,0 +1,281 @@ +/* + * + * 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 + * + * + * Authors: + * Michael Zucchi + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include + +#include +#include +#include + +/* This isn't as portable as, say, the stuff in GNU coreutils. But I care not for OSF1. */ +#ifdef HAVE_STATVFS +# ifdef HAVE_SYS_STATVFS_H +# include +# endif +#else +#ifdef HAVE_STATFS +# ifdef HAVE_SYS_PARAM_H +# include /* bsd interface */ +# endif +# ifdef HAVE_SYS_MOUNT_H +# include +# endif +#endif +#endif + +#include +#include + +#include +#include +#include + +#include "e-file-utils.h" +#include "e-io-activity.h" + +static void +file_replace_contents_cb (GFile *file, + GAsyncResult *result, + EActivity *activity) +{ + gchar *new_etag; + gboolean success; + GError *error = NULL; + + success = g_file_replace_contents_finish ( + file, result, &new_etag, &error); + + result = e_io_activity_get_async_result (E_IO_ACTIVITY (activity)); + + g_object_set_data_full ( + G_OBJECT (result), + "__new_etag__", new_etag, + (GDestroyNotify) g_free); + + g_simple_async_result_set_op_res_gboolean ( + G_SIMPLE_ASYNC_RESULT (result), success); + + if (error != NULL) { + g_simple_async_result_set_from_error ( + G_SIMPLE_ASYNC_RESULT (result), error); + g_error_free (error); + } + + e_activity_complete (activity); + + g_object_unref (activity); +} + +EActivity * +e_file_replace_contents_async (GFile *file, + const gchar *contents, + gsize length, + const gchar *etag, + gboolean make_backup, + GFileCreateFlags flags, + GAsyncReadyCallback callback, + gpointer user_data) +{ + EActivity *activity; + GSimpleAsyncResult *simple; + GCancellable *cancellable; + const gchar *format; + gchar *description; + gchar *basename; + gchar *filename; + gchar *hostname; + gchar *uri; + + g_return_val_if_fail (G_IS_FILE (file), NULL); + g_return_val_if_fail (contents != NULL, NULL); + + uri = g_file_get_uri (file); + filename = g_filename_from_uri (uri, &hostname, NULL); + basename = g_filename_display_basename (filename); + + if (hostname != NULL) { + /* Translators: The string value is the basename of a file. */ + format = _("Writing \"%s\""); + description = g_strdup_printf (format, basename); + } else { + /* Translators: The first string value is the basename of a + * remote file, the second string value is the hostname. */ + format = _("Writing \"%s\" to %s"); + description = g_strdup_printf (format, basename, hostname); + } + + cancellable = g_cancellable_new (); + + simple = g_simple_async_result_new ( + G_OBJECT (file), callback, user_data, + e_file_replace_contents_async); + + activity = e_io_activity_new ( + description, G_ASYNC_RESULT (simple), cancellable); + + g_file_replace_contents_async ( + file, contents, length, etag, + make_backup, flags, cancellable, + (GAsyncReadyCallback) file_replace_contents_cb, + activity); + + g_object_unref (cancellable); + g_object_unref (simple); + + g_free (description); + g_free (basename); + g_free (filename); + g_free (hostname); + g_free (uri); + + return activity; +} + +gboolean +e_file_replace_contents_finish (GFile *file, + GAsyncResult *result, + gchar **new_etag, + GError **error) +{ + GSimpleAsyncResult *simple; + + g_return_val_if_fail (G_IS_FILE (file), FALSE); + g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + + if (g_simple_async_result_propagate_error (simple, error)) + return FALSE; + + if (new_etag != NULL) + *new_etag = g_object_steal_data ( + G_OBJECT (result), "__new_etag__"); + + return TRUE; +} + +/** + * e_fsutils_usage: + * @path: + * + * Calculate the amount of disk space used by a given path. + * + * Return value: The number of 1024 byte blocks used by the + * filesystem. + **/ +glong e_fsutils_usage(const gchar *inpath) +{ + GDir *dir; + const gchar *d; + long size = 0; + GSList *paths; + + /* iterative, depth-first scan, because i can ... */ + paths = g_slist_prepend(NULL, g_strdup(inpath)); + + while (paths) { + gchar *path = paths->data; + + paths = g_slist_remove_link(paths, paths); + + dir = g_dir_open(path, 0, NULL); + if (dir == NULL) { + g_free(path); + goto fail; + } + + while ((d = g_dir_read_name(dir))) { + gchar *full_path; + struct stat st; + + full_path = g_build_filename(path, d, NULL); + if (g_stat(full_path, &st) == -1) { + g_free(full_path); + g_dir_close(dir); + g_free(path); + goto fail; + } else if (S_ISDIR(st.st_mode)) { + paths = g_slist_prepend(paths, full_path); + full_path = NULL; + } else if (S_ISREG(st.st_mode)) { + /* This is in 512 byte blocks. st_blksize is page size on linux, + on *BSD it might be significant. */ +#ifndef G_OS_WIN32 + size += st.st_blocks/2; +#endif + } + + g_free(full_path); + } + + g_dir_close(dir); + g_free(path); + } + + return size; + +fail: + g_slist_foreach(paths, (GFunc)g_free, NULL); + g_slist_free(paths); + + return -1; +} + +/** + * e_fsutils_avail: + * @path: + * + * Find the available disk space at the given path. + * + * Return value: -1 if it could not be determined, otherwise the + * number of disk blocks, expressed as system-independent, 1024 byte + * blocks. + **/ +glong +e_fsutils_avail(const gchar *path) +{ +#if defined(HAVE_STATVFS) + struct statvfs stfs; + + if (statvfs(path, &stfs) == -1) + return -1; + + /* Assumes that frsize === power of 2 */ + if (stfs.f_frsize >= 1024) + return stfs.f_bavail * (stfs.f_frsize / 1024); + else + return stfs.f_bavail / (1024 / stfs.f_frsize); +#elif defined(HAVE_STATFS) + struct statfs stfs; + + if (statfs(path, &stfs) == -1) + return -1; + + /* For BSD this isn't clear, it may be dependent on f_bsize */ + return stfs.f_bavail / 2; +#else + errno = ENOSYS; + return -1; +#endif +} + -- cgit