evolution-3.6.4/e-util/e-file-utils.c

No issues found

  1 /*
  2  *
  3  * This program is free software; you can redistribute it and/or
  4  * modify it under the terms of the GNU Lesser General Public
  5  * License as published by the Free Software Foundation; either
  6  * version 2 of the License, or (at your option) version 3.
  7  *
  8  * This program is distributed in the hope that it will be useful,
  9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 11  * Lesser General Public License for more details.
 12  *
 13  * You should have received a copy of the GNU Lesser General Public
 14  * License along with the program; if not, see <http://www.gnu.org/licenses/>
 15  *
 16  *
 17  * Authors:
 18  *		Michael Zucchi <notzed@ximian.com>
 19  *
 20  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 21  *
 22  */
 23 
 24 #ifdef HAVE_CONFIG_H
 25 #include <config.h>
 26 #endif
 27 
 28 #include <sys/types.h>
 29 #include <sys/stat.h>
 30 #include <unistd.h>
 31 
 32 /* This isn't as portable as, say, the stuff in GNU coreutils.
 33  * But I care not for OSF1. */
 34 #ifdef HAVE_STATVFS
 35 # ifdef HAVE_SYS_STATVFS_H
 36 #  include <sys/statvfs.h>
 37 # endif
 38 #else
 39 #ifdef HAVE_STATFS
 40 # ifdef HAVE_SYS_PARAM_H
 41 #  include <sys/param.h>	/* bsd interface */
 42 # endif
 43 # ifdef HAVE_SYS_MOUNT_H
 44 #  include <sys/mount.h>
 45 # endif
 46 #endif
 47 #endif
 48 
 49 #include <errno.h>
 50 #include <string.h>
 51 
 52 #include <glib/gstdio.h>
 53 #include <glib/gi18n-lib.h>
 54 
 55 #include "e-activity.h"
 56 #include "e-file-utils.h"
 57 
 58 typedef struct _AsyncContext AsyncContext;
 59 
 60 struct _AsyncContext {
 61 	EActivity *activity;
 62 	gchar *new_etag;
 63 };
 64 
 65 static void
 66 async_context_free (AsyncContext *context)
 67 {
 68 	if (context->activity != NULL)
 69 		g_object_unref (context->activity);
 70 
 71 	g_free (context->new_etag);
 72 
 73 	g_slice_free (AsyncContext, context);
 74 }
 75 
 76 static void
 77 file_replace_contents_cb (GFile *file,
 78                           GAsyncResult *result,
 79                           GSimpleAsyncResult *simple)
 80 {
 81 	AsyncContext *context;
 82 	gchar *new_etag = NULL;
 83 	GError *error = NULL;
 84 
 85 	context = g_simple_async_result_get_op_res_gpointer (simple);
 86 
 87 	g_file_replace_contents_finish (file, result, &new_etag, &error);
 88 
 89 	if (!e_activity_handle_cancellation (context->activity, error))
 90 		e_activity_set_state (context->activity, E_ACTIVITY_COMPLETED);
 91 
 92 	if (error == NULL)
 93 		context->new_etag = new_etag;
 94 	else {
 95 		g_warn_if_fail (new_etag == NULL);
 96 		g_simple_async_result_take_error (simple, error);
 97 	}
 98 
 99 	g_simple_async_result_complete (simple);
100 
101 	g_object_unref (simple);
102 }
103 
104 /**
105  * e_file_replace_contents_async:
106  * @file: input #GFile
107  * @contents: string of contents to replace the file with
108  * @length: the length of @contents in bytes
109  * @etag: a new entity tag for the @file, or %NULL
110  * @make_backup: %TRUE if a backup should be created
111  * @flags: a set of #GFileCreateFlags
112  * @callback: a #GAsyncReadyCallback to call when the request is satisfied
113  * @user_data: the data to pass to the callback function
114  *
115  * This is a wrapper for g_file_replace_contents_async() that also returns
116  * an #EActivity to track the file operation.  Cancelling the activity will
117  * cancel the file operation.  See g_file_replace_contents_async() for more
118  * details.
119  *
120  * Returns: an #EActivity for the file operation
121  **/
122 EActivity *
123 e_file_replace_contents_async (GFile *file,
124                                const gchar *contents,
125                                gsize length,
126                                const gchar *etag,
127                                gboolean make_backup,
128                                GFileCreateFlags flags,
129                                GAsyncReadyCallback callback,
130                                gpointer user_data)
131 {
132 	GSimpleAsyncResult *simple;
133 	GCancellable *cancellable;
134 	AsyncContext *context;
135 	const gchar *format;
136 	gchar *description;
137 	gchar *basename;
138 	gchar *filename;
139 	gchar *hostname;
140 	gchar *uri;
141 
142 	g_return_val_if_fail (G_IS_FILE (file), NULL);
143 	g_return_val_if_fail (contents != NULL, NULL);
144 
145 	uri = g_file_get_uri (file);
146 	filename = g_filename_from_uri (uri, &hostname, NULL);
147 	if (filename != NULL)
148 		basename = g_filename_display_basename (filename);
149 	else
150 		basename = g_strdup (_("(Unknown Filename)"));
151 
152 	if (hostname == NULL) {
153 		/* Translators: The string value is the basename of a file. */
154 		format = _("Writing \"%s\"");
155 		description = g_strdup_printf (format, basename);
156 	} else {
157 		/* Translators: The first string value is the basename of a
158 		 * remote file, the second string value is the hostname. */
159 		format = _("Writing \"%s\" to %s");
160 		description = g_strdup_printf (format, basename, hostname);
161 	}
162 
163 	cancellable = g_cancellable_new ();
164 
165 	context = g_slice_new0 (AsyncContext);
166 	context->activity = e_activity_new ();
167 
168 	e_activity_set_text (context->activity, description);
169 	e_activity_set_cancellable (context->activity, cancellable);
170 
171 	simple = g_simple_async_result_new (
172 		G_OBJECT (file), callback, user_data,
173 		e_file_replace_contents_async);
174 
175 	g_simple_async_result_set_check_cancellable (simple, cancellable);
176 
177 	g_simple_async_result_set_op_res_gpointer (
178 		simple, context, (GDestroyNotify) async_context_free);
179 
180 	g_file_replace_contents_async (
181 		file, contents, length, etag,
182 		make_backup, flags, cancellable,
183 		(GAsyncReadyCallback) file_replace_contents_cb,
184 		simple);
185 
186 	g_object_unref (cancellable);
187 
188 	g_free (description);
189 	g_free (basename);
190 	g_free (filename);
191 	g_free (hostname);
192 	g_free (uri);
193 
194 	return context->activity;
195 }
196 
197 /**
198  * e_file_replace_contents_finish:
199  * @file: input #GFile
200  * @result: a #GAsyncResult
201  * @new_etag: return location for a new entity tag
202  * @error: return location for a #GError, or %NULL
203  *
204  * Finishes an asynchronous replace of the given @file.  See
205  * e_file_replace_contents_async().  Sets @new_etag to the new entity
206  * tag for the document, if present.  Free it with g_free() when it is
207  * no longer needed.
208  *
209  * Returns: %TRUE on success, %FALSE on failure
210  **/
211 gboolean
212 e_file_replace_contents_finish (GFile *file,
213                                 GAsyncResult *result,
214                                 gchar **new_etag,
215                                 GError **error)
216 {
217 	GSimpleAsyncResult *simple;
218 	AsyncContext *context;
219 
220 	g_return_val_if_fail (G_IS_FILE (file), FALSE);
221 	g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE);
222 
223 	simple = G_SIMPLE_ASYNC_RESULT (result);
224 	context = g_simple_async_result_get_op_res_gpointer (simple);
225 
226 	if (g_simple_async_result_propagate_error (simple, error))
227 		return FALSE;
228 
229 	if (new_etag != NULL)
230 		*new_etag = g_strdup (context->new_etag);
231 
232 	return TRUE;
233 }