"Initial commit to Gerrit"
[profile/ivi/libgsf.git] / gsf-gnome / gsf-output-gnomevfs.c
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * gsf-output-gnomevfs.c: gnomevfs based output
4  *
5  * Copyright (C) 2002-2004 Dom Lachowicz (cinamod@hotmail.com)
6  *
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.
10  *
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.
15  *
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
19  * USA
20  */
21
22 #include <gsf-config.h>
23
24 #ifdef LIBGSF_GNOMEVFS_VIA_GIO
25 #include <gsf/gsf-output-gio.h>
26 #define GnomeVFSHandle void
27 #define GnomeVFSURI void
28 #endif
29
30 #include <gsf-gnome/gsf-output-gnomevfs.h>
31 #include <gsf/gsf-output-impl.h>
32 #include <gsf/gsf-impl-utils.h>
33
34
35 struct _GsfOutputGnomeVFS {
36     GsfOutput output;
37
38     GnomeVFSHandle *handle;
39 };
40
41 typedef struct {
42     GsfOutputClass output_class;
43 } GsfOutputGnomeVFSClass;
44
45 #ifdef LIBGSF_GNOMEVFS_VIA_GIO
46
47 GType
48 gsf_output_gnomevfs_get_type (void)
49 {
50         return gsf_output_gio_get_type ();
51 }
52
53 GsfOutput *
54 gsf_output_gnomevfs_new (char const *uri, GError **error)
55 {
56         return gsf_output_gio_new_for_uri (uri, error);
57 }
58
59 GsfOutput *
60 gsf_output_gnomevfs_new_uri (GnomeVFSURI *uri, GError **error)
61 {
62         static gboolean tried = FALSE;
63         static char * (*h_g_vfs_uri_to_string) (const GnomeVFSURI *uri, int);
64
65         if (!tried) {
66                 gpointer p;
67                 GModule *module;
68
69                 tried = TRUE;
70                 module = g_module_open (NULL, 0);
71                 if (module) {
72                         if (g_module_symbol (module, "gnome_vfs_uri_to_string",
73                                              &p))
74                                 h_g_vfs_uri_to_string = p;
75                         g_module_close (module);
76                 }
77         }
78
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);
82                 g_free (uritxt);
83                 return res;
84         }
85
86         g_set_error (error, gsf_output_error_id (), 0,
87                      "Failed to interface to gnome-vfs");
88         return NULL;
89 }
90
91 #else
92
93 /**
94  * gsf_output_gnomevfs_new :
95  * @text_uri : in utf8.
96  * @err      : optionally %NULL.
97  *
98  * Returns: a new file or %NULL.
99  **/
100 GsfOutput *
101 gsf_output_gnomevfs_new (char const *text_uri, GError **err)
102 {
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);
106         return res;
107 }
108
109 /**
110  * gsf_output_gnomevfs_new_uri :
111  * @uri      : resource indicator
112  * @err      : optionally %NULL.
113  *
114  * Returns: a new file or %NULL.
115  **/
116 GsfOutput *
117 gsf_output_gnomevfs_new_uri (GnomeVFSURI * uri, GError **err)
118 {
119         GsfOutputGnomeVFS *output;
120         GnomeVFSHandle *handle;
121         GnomeVFSResult res;
122         int perms = -1;
123
124         if (uri == NULL) {
125                 g_set_error (err, gsf_output_error_id (), 0,
126                              "Filename/URI cannot be NULL");
127                 return NULL;
128         }
129
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;
135
136                 info = gnome_vfs_file_info_new ();
137                 res = gnome_vfs_get_file_info_uri (uri,
138                                                    info,
139                                                    GNOME_VFS_FILE_INFO_FOLLOW_LINKS|GNOME_VFS_FILE_INFO_GET_ACCESS_RIGHTS);
140
141                 if ((res == GNOME_VFS_OK) && (info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS)) {
142                         perms = info->permissions;
143                 } 
144
145                 gnome_vfs_file_info_unref (info);
146         }
147
148         if (perms == -1) {
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);
152
153                 if (res != GNOME_VFS_OK) {
154                         res = gnome_vfs_create_uri (&handle, uri, GNOME_VFS_OPEN_WRITE|GNOME_VFS_OPEN_RANDOM, FALSE, 0644);
155                 }
156         } else {
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);
160
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);
164                 }
165         }
166
167         if (res != GNOME_VFS_OK) {
168                 g_set_error (err, gsf_output_error_id (), (gint) res,
169                              gnome_vfs_result_to_string (res));
170                 return NULL;
171         }
172
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);
177
178         output = g_object_new (GSF_OUTPUT_GNOMEVFS_TYPE, NULL);
179         if (G_UNLIKELY (NULL == output)) {
180                 if (handle != NULL)
181                         gnome_vfs_close (handle);
182                 return NULL;
183         }
184         output->handle = handle;
185
186         return GSF_OUTPUT (output);
187 }
188
189 static gboolean
190 gsf_output_gnomevfs_close (GsfOutput *output)
191 {
192     GsfOutputGnomeVFS *vfs = GSF_OUTPUT_GNOMEVFS (output);
193     gboolean res = FALSE;
194
195     if (vfs->handle != NULL) {
196         res = (GNOME_VFS_OK == gnome_vfs_close (vfs->handle));
197         vfs->handle = NULL;
198     }
199
200     return res;
201 }
202
203 static void
204 gsf_output_gnomevfs_finalize (GObject *obj)
205 {
206     GObjectClass *parent_class;
207     GsfOutput *output = (GsfOutput *)obj;
208
209     gsf_output_gnomevfs_close (output);
210
211     parent_class = g_type_class_peek (GSF_OUTPUT_TYPE);
212     if (parent_class && parent_class->finalize)
213         parent_class->finalize (obj);
214 }
215
216 static gboolean
217 gsf_output_gnomevfs_seek (GsfOutput *output, gsf_off_t offset,
218                           GSeekType whence)
219 {
220         GsfOutputGnomeVFS const *vfs = GSF_OUTPUT_GNOMEVFS (output);
221         GnomeVFSSeekPosition    vfs_whence = 0; /* make compiler shut up */
222         GnomeVFSResult          res;
223
224         g_return_val_if_fail (vfs->handle != NULL, 
225                 gsf_output_set_error (output, 0, "missing handle"));
226
227         switch (whence) {
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;
231         default :
232                 break; /*checked in GsfOutput wrapper */
233         }
234
235         res = gnome_vfs_seek (vfs->handle, vfs_whence,
236                               (GnomeVFSFileOffset) offset);
237         if (GNOME_VFS_OK == res)
238                 return TRUE;
239         return gsf_output_set_error (output, 0,
240                 gnome_vfs_result_to_string (res));
241 }
242
243 static gboolean
244 gsf_output_gnomevfs_write (GsfOutput *output,
245                            size_t num_bytes,
246                            guint8 const *buffer)
247 {
248     GsfOutputGnomeVFS *vfs = GSF_OUTPUT_GNOMEVFS (output);
249     GnomeVFSFileSize nwritten = 0, total_written = 0;
250     GnomeVFSResult res = GNOME_VFS_OK;
251
252     g_return_val_if_fail (vfs != NULL, FALSE);
253     g_return_val_if_fail (vfs->handle != NULL, FALSE);
254
255     while ((res == GNOME_VFS_OK) && (total_written < num_bytes))
256             {
257                     res = gnome_vfs_write (vfs->handle, (gconstpointer)(buffer + total_written),
258                                            (GnomeVFSFileSize)(num_bytes - total_written), &nwritten);
259                     total_written += nwritten;
260             }
261     return (res == GNOME_VFS_OK && total_written == num_bytes);
262 }
263
264 static void
265 gsf_output_gnomevfs_init (GObject *obj)
266 {
267     GsfOutputGnomeVFS *vfs = GSF_OUTPUT_GNOMEVFS (obj);
268
269     vfs->handle = NULL;
270 }
271
272 static void
273 gsf_output_gnomevfs_class_init (GObjectClass *gobject_class)
274 {
275     GsfOutputClass *output_class = GSF_OUTPUT_CLASS (gobject_class);
276
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;
281 }
282
283 GSF_CLASS (GsfOutputGnomeVFS, gsf_output_gnomevfs,
284            gsf_output_gnomevfs_class_init, gsf_output_gnomevfs_init, GSF_OUTPUT_TYPE)
285
286 #endif