1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * gsf-output-gnomevfs.c: gnomevfs based output
5 * Copyright (C) 2002-2004 Dom Lachowicz (cinamod@hotmail.com)
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of version 2.1 of the GNU Lesser General Public
9 * License as published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
22 #include <gsf-config.h>
24 #ifdef LIBGSF_GNOMEVFS_VIA_GIO
25 #include <gsf/gsf-output-gio.h>
26 #define GnomeVFSHandle void
27 #define GnomeVFSURI void
30 #include <gsf-gnome/gsf-output-gnomevfs.h>
31 #include <gsf/gsf-output-impl.h>
32 #include <gsf/gsf-impl-utils.h>
35 struct _GsfOutputGnomeVFS {
38 GnomeVFSHandle *handle;
42 GsfOutputClass output_class;
43 } GsfOutputGnomeVFSClass;
45 #ifdef LIBGSF_GNOMEVFS_VIA_GIO
48 gsf_output_gnomevfs_get_type (void)
50 return gsf_output_gio_get_type ();
54 gsf_output_gnomevfs_new (char const *uri, GError **error)
56 return gsf_output_gio_new_for_uri (uri, error);
60 gsf_output_gnomevfs_new_uri (GnomeVFSURI *uri, GError **error)
62 static gboolean tried = FALSE;
63 static char * (*h_g_vfs_uri_to_string) (const GnomeVFSURI *uri, int);
70 module = g_module_open (NULL, 0);
72 if (g_module_symbol (module, "gnome_vfs_uri_to_string",
74 h_g_vfs_uri_to_string = p;
75 g_module_close (module);
79 if (h_g_vfs_uri_to_string) {
80 char *uritxt = h_g_vfs_uri_to_string (uri, 0);
81 GsfOutput *res = gsf_output_gio_new_for_uri (uritxt, error);
86 g_set_error (error, gsf_output_error_id (), 0,
87 "Failed to interface to gnome-vfs");
94 * gsf_output_gnomevfs_new :
95 * @text_uri : in utf8.
96 * @err : optionally %NULL.
98 * Returns: a new file or %NULL.
101 gsf_output_gnomevfs_new (char const *text_uri, GError **err)
103 GnomeVFSURI *uri = gnome_vfs_uri_new (text_uri);
104 GsfOutput *res = gsf_output_gnomevfs_new_uri (uri, err);
105 gnome_vfs_uri_unref (uri);
110 * gsf_output_gnomevfs_new_uri :
111 * @uri : resource indicator
112 * @err : optionally %NULL.
114 * Returns: a new file or %NULL.
117 gsf_output_gnomevfs_new_uri (GnomeVFSURI * uri, GError **err)
119 GsfOutputGnomeVFS *output;
120 GnomeVFSHandle *handle;
125 g_set_error (err, gsf_output_error_id (), 0,
126 "Filename/URI cannot be NULL");
130 if (gnome_vfs_uri_exists (uri)) {
131 /* see bug 159442 - if the file exists, we want to do our best to preserve existing
132 * pemissions AND truncate the file. that is, we want to emulate truncate() in case
133 * a gnomevfs backend doesn't support it */
134 GnomeVFSFileInfo *info;
136 info = gnome_vfs_file_info_new ();
137 res = gnome_vfs_get_file_info_uri (uri,
139 GNOME_VFS_FILE_INFO_FOLLOW_LINKS|GNOME_VFS_FILE_INFO_GET_ACCESS_RIGHTS);
141 if ((res == GNOME_VFS_OK) && (info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS)) {
142 perms = info->permissions;
145 gnome_vfs_file_info_unref (info);
149 /* we didn't get the permissions, but calling open_uri() with OPEN_WRITE set will create the file for us.
150 * if the uri_exists(), let's hope that truncate() works. */
151 res = gnome_vfs_open_uri (&handle, uri, GNOME_VFS_OPEN_WRITE|GNOME_VFS_OPEN_RANDOM);
153 if (res != GNOME_VFS_OK) {
154 res = gnome_vfs_create_uri (&handle, uri, GNOME_VFS_OPEN_WRITE|GNOME_VFS_OPEN_RANDOM, FALSE, 0644);
157 /* we got the permissions, so let's call create() with the existing permissions instead of open() since
158 * create() will truncate the file for us. */
159 res = gnome_vfs_create_uri (&handle, uri, GNOME_VFS_OPEN_WRITE|GNOME_VFS_OPEN_RANDOM, FALSE, perms);
161 if (res != GNOME_VFS_OK) {
162 /* create() failed. let's see if we can open_uri() instead and hope that truncate works. */
163 res = gnome_vfs_open_uri (&handle, uri, GNOME_VFS_OPEN_WRITE|GNOME_VFS_OPEN_RANDOM);
167 if (res != GNOME_VFS_OK) {
168 g_set_error (err, gsf_output_error_id (), (gint) res,
169 gnome_vfs_result_to_string (res));
173 /* truncate the file to length 0 so if we overwrite a file smaller than
174 * it was before, it doesn't show the rest of the old file (Bug: 159442).
175 * for many gnomevfs backends, this might actually be a noop */
176 gnome_vfs_truncate_handle(handle, 0);
178 output = g_object_new (GSF_OUTPUT_GNOMEVFS_TYPE, NULL);
179 if (G_UNLIKELY (NULL == output)) {
181 gnome_vfs_close (handle);
184 output->handle = handle;
186 return GSF_OUTPUT (output);
190 gsf_output_gnomevfs_close (GsfOutput *output)
192 GsfOutputGnomeVFS *vfs = GSF_OUTPUT_GNOMEVFS (output);
193 gboolean res = FALSE;
195 if (vfs->handle != NULL) {
196 res = (GNOME_VFS_OK == gnome_vfs_close (vfs->handle));
204 gsf_output_gnomevfs_finalize (GObject *obj)
206 GObjectClass *parent_class;
207 GsfOutput *output = (GsfOutput *)obj;
209 gsf_output_gnomevfs_close (output);
211 parent_class = g_type_class_peek (GSF_OUTPUT_TYPE);
212 if (parent_class && parent_class->finalize)
213 parent_class->finalize (obj);
217 gsf_output_gnomevfs_seek (GsfOutput *output, gsf_off_t offset,
220 GsfOutputGnomeVFS const *vfs = GSF_OUTPUT_GNOMEVFS (output);
221 GnomeVFSSeekPosition vfs_whence = 0; /* make compiler shut up */
224 g_return_val_if_fail (vfs->handle != NULL,
225 gsf_output_set_error (output, 0, "missing handle"));
228 case G_SEEK_SET : vfs_whence = GNOME_VFS_SEEK_START; break;
229 case G_SEEK_CUR : vfs_whence = GNOME_VFS_SEEK_CURRENT; break;
230 case G_SEEK_END : vfs_whence = GNOME_VFS_SEEK_END; break;
232 break; /*checked in GsfOutput wrapper */
235 res = gnome_vfs_seek (vfs->handle, vfs_whence,
236 (GnomeVFSFileOffset) offset);
237 if (GNOME_VFS_OK == res)
239 return gsf_output_set_error (output, 0,
240 gnome_vfs_result_to_string (res));
244 gsf_output_gnomevfs_write (GsfOutput *output,
246 guint8 const *buffer)
248 GsfOutputGnomeVFS *vfs = GSF_OUTPUT_GNOMEVFS (output);
249 GnomeVFSFileSize nwritten = 0, total_written = 0;
250 GnomeVFSResult res = GNOME_VFS_OK;
252 g_return_val_if_fail (vfs != NULL, FALSE);
253 g_return_val_if_fail (vfs->handle != NULL, FALSE);
255 while ((res == GNOME_VFS_OK) && (total_written < num_bytes))
257 res = gnome_vfs_write (vfs->handle, (gconstpointer)(buffer + total_written),
258 (GnomeVFSFileSize)(num_bytes - total_written), &nwritten);
259 total_written += nwritten;
261 return (res == GNOME_VFS_OK && total_written == num_bytes);
265 gsf_output_gnomevfs_init (GObject *obj)
267 GsfOutputGnomeVFS *vfs = GSF_OUTPUT_GNOMEVFS (obj);
273 gsf_output_gnomevfs_class_init (GObjectClass *gobject_class)
275 GsfOutputClass *output_class = GSF_OUTPUT_CLASS (gobject_class);
277 gobject_class->finalize = gsf_output_gnomevfs_finalize;
278 output_class->Close = gsf_output_gnomevfs_close;
279 output_class->Seek = gsf_output_gnomevfs_seek;
280 output_class->Write = gsf_output_gnomevfs_write;
283 GSF_CLASS (GsfOutputGnomeVFS, gsf_output_gnomevfs,
284 gsf_output_gnomevfs_class_init, gsf_output_gnomevfs_init, GSF_OUTPUT_TYPE)