root/trunk/libtinymail-gnomevfs/tny-vfs-stream.c

Revision 3823 (checked in by svillar, 2 weeks ago)

Some misc fixes

Line 
1 /* libtinymail-gnomevfs - The Tiny Mail base library for GnomeVFS
2  * Copyright (C) 2006-2007 Philip Van Hoof <pvanhoof@gnome.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with self library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  *
19  * A GnomeVFS to CamelStream mapper.
20  */
21
22 #include <string.h>
23 #include <stdio.h>
24 #include <errno.h>
25
26 #include <tny-vfs-stream.h>
27
28 static GObjectClass *parent_class = NULL;
29
30 typedef struct _TnyVfsStreamPriv TnyVfsStreamPriv;
31
32 struct _TnyVfsStreamPriv
33 {
34         GnomeVFSHandle *handle;
35         gboolean eos;
36         off_t position;         /* current postion in the stream */
37         off_t bound_start;      /* first valid position */
38         off_t bound_end;        /* first invalid position */
39 };
40
41 #define TNY_VFS_STREAM_GET_PRIVATE(o) \
42         (G_TYPE_INSTANCE_GET_PRIVATE ((o), TNY_TYPE_VFS_STREAM, TnyVfsStreamPriv))
43
44
45 static void
46 tny_vfs_stream_set_errno (GnomeVFSResult res)
47 {
48         switch(res) {
49         case GNOME_VFS_OK:
50                 g_warning("tny-vfs-stream: calling set_errno with no error");
51                 break;
52         case GNOME_VFS_ERROR_NOT_FOUND:
53         case GNOME_VFS_ERROR_HOST_NOT_FOUND:
54         case GNOME_VFS_ERROR_INVALID_HOST_NAME:
55         case GNOME_VFS_ERROR_HOST_HAS_NO_ADDRESS:
56         case GNOME_VFS_ERROR_SERVICE_NOT_AVAILABLE:
57                 errno = ENOENT;
58                 break;
59         case GNOME_VFS_ERROR_GENERIC:
60         case GNOME_VFS_ERROR_INTERNAL:
61         case GNOME_VFS_ERROR_IO:
62         case GNOME_VFS_ERROR_EOF: /* will be caught by read before here anyway */
63         case GNOME_VFS_ERROR_SERVICE_OBSOLETE:
64         case GNOME_VFS_ERROR_PROTOCOL_ERROR:
65         default:
66                 errno = EIO;
67                 break;
68         case GNOME_VFS_ERROR_BAD_PARAMETERS:
69         case GNOME_VFS_ERROR_NOT_SUPPORTED:
70         case GNOME_VFS_ERROR_INVALID_URI:
71         case GNOME_VFS_ERROR_NOT_OPEN:
72         case GNOME_VFS_ERROR_INVALID_OPEN_MODE:
73         case GNOME_VFS_ERROR_NOT_SAME_FILE_SYSTEM:
74                 errno = EINVAL;
75                 break;
76         case GNOME_VFS_ERROR_CORRUPTED_DATA: /* not sure about these */
77         case GNOME_VFS_ERROR_WRONG_FORMAT:
78         case GNOME_VFS_ERROR_BAD_FILE:
79                 errno = EBADF;
80                 break;
81         case GNOME_VFS_ERROR_TOO_BIG:
82                 errno = E2BIG;
83                 break;
84         case GNOME_VFS_ERROR_NO_SPACE:
85                 errno = ENOSPC;
86                 break;
87         case GNOME_VFS_ERROR_READ_ONLY:
88         case GNOME_VFS_ERROR_READ_ONLY_FILE_SYSTEM:
89                 errno = EROFS;
90                 break;
91         case GNOME_VFS_ERROR_TOO_MANY_OPEN_FILES:
92                 errno = EMFILE;
93                 break;
94         case GNOME_VFS_ERROR_NOT_A_DIRECTORY:
95                 errno = ENOTDIR;
96                 break;
97         case GNOME_VFS_ERROR_IN_PROGRESS:
98                 errno = EINPROGRESS;
99                 break;
100         case GNOME_VFS_ERROR_INTERRUPTED:
101                 errno = EINTR;
102                 break;
103         case GNOME_VFS_ERROR_FILE_EXISTS:
104                 errno = EEXIST;
105         case GNOME_VFS_ERROR_LOOP:
106                 errno = ELOOP;
107                 break;
108         case GNOME_VFS_ERROR_ACCESS_DENIED:
109         case GNOME_VFS_ERROR_NOT_PERMITTED:
110         case GNOME_VFS_ERROR_LOGIN_FAILED:
111                 errno = EPERM;
112                 break;
113         case GNOME_VFS_ERROR_IS_DIRECTORY:
114         case GNOME_VFS_ERROR_DIRECTORY_NOT_EMPTY: /* ?? */
115                 errno = EISDIR;
116                 break;
117         case GNOME_VFS_ERROR_NO_MEMORY:
118                 errno = ENOMEM;
119                 break;
120         case GNOME_VFS_ERROR_CANCELLED:
121                 errno = EINTR;
122                 break;
123         case GNOME_VFS_ERROR_DIRECTORY_BUSY:
124                 errno = EBUSY;
125                 break;
126         case GNOME_VFS_ERROR_TOO_MANY_LINKS:
127                 errno = EMLINK;
128                 break;
129         case GNOME_VFS_ERROR_NAME_TOO_LONG:
130                 errno = ENAMETOOLONG;
131                 break;
132         }
133 }
134
135 static gssize
136 tny_vfs_stream_write_to_stream (TnyStream *self, TnyStream *output)
137 {
138         char tmp_buf[4096];
139         gssize total = 0;
140         gssize nb_read;
141         gssize nb_written;
142
143         g_assert (TNY_IS_STREAM (output));
144
145         while (G_UNLIKELY (!tny_stream_is_eos (self))) {
146                 nb_read = tny_stream_read (self, tmp_buf, sizeof (tmp_buf));
147                 if (G_UNLIKELY (nb_read < 0))
148                         return -1;
149                 else if (G_LIKELY (nb_read > 0)) {
150                         nb_written = 0;
151        
152                         while (G_LIKELY (nb_written < nb_read))
153                         {
154                                 gssize len = tny_stream_write (output, tmp_buf + nb_written,
155                                                                   nb_read - nb_written);
156                                 if (G_UNLIKELY (len < 0))
157                                         return -1;
158                                 nb_written += len;
159                         }
160                         total += nb_written;
161                 }
162         }
163         return total;
164 }
165
166 static gssize
167 tny_vfs_stream_read  (TnyStream *self, char *buffer, gsize n)
168 {
169         TnyVfsStreamPriv *priv = TNY_VFS_STREAM_GET_PRIVATE (self);
170         GnomeVFSFileSize nread = 0;
171         GnomeVFSResult result;
172
173         if (priv->bound_end != (~0))
174                 n = MIN (priv->bound_end - priv->position, n);
175
176         result = gnome_vfs_read (priv->handle, buffer, n, &nread);
177
178         if (nread > 0 && result == GNOME_VFS_OK)
179                 priv->position += nread;
180         else {
181                 if ((result != GNOME_VFS_OK) && (result != GNOME_VFS_ERROR_EOF))
182                         nread = -1;
183                 else if (nread == 0)
184                         priv->eos = TRUE;
185                 tny_vfs_stream_set_errno (result);
186         }
187
188         return nread;
189 }
190
191 static gssize
192 tny_vfs_stream_write (TnyStream *self, const char *buffer, gsize n)
193 {
194         TnyVfsStreamPriv *priv = TNY_VFS_STREAM_GET_PRIVATE (self);
195         GnomeVFSFileSize nwritten = 0;
196         GnomeVFSResult result;
197
198         if (priv->bound_end != (~0))
199                 n = MIN (priv->bound_end - priv->position, n);
200
201         result = gnome_vfs_write (priv->handle, buffer, n, &nwritten);
202
203         if (nwritten > 0 && result == GNOME_VFS_OK)
204                 priv->position += nwritten;
205         else
206                 tny_vfs_stream_set_errno (result);
207
208         return nwritten;
209 }
210
211 static gint
212 tny_vfs_stream_close (TnyStream *self)
213 {
214         TnyVfsStreamPriv *priv = TNY_VFS_STREAM_GET_PRIVATE (self);
215         GnomeVFSResult res;
216
217         if (priv->handle == NULL)  {
218                 errno = EINVAL;
219                 return -1;
220         }
221
222         res = gnome_vfs_close (priv->handle);
223
224         priv->handle = NULL;
225         priv->eos = TRUE;
226
227         if (res == GNOME_VFS_OK)
228                 return 0;
229
230         tny_vfs_stream_set_errno (res);
231
232         return -1;
233 }
234
235
236 /**
237  * tny_vfs_stream_set_handle:
238  * @self: A #TnyVfsStream instance
239  * @handle: The #GnomeVFSHandle to write to or read from
240  *
241  * Set the #GnomeVFSHandle to play adaptor for
242  *
243  **/
244 void
245 tny_vfs_stream_set_handle (TnyVfsStream *self, GnomeVFSHandle *handle)
246 {
247         TnyVfsStreamPriv *priv = TNY_VFS_STREAM_GET_PRIVATE (self);
248
249         if (priv->handle) {
250                 gnome_vfs_close (priv->handle);
251                 priv->handle = NULL;
252         }
253
254         if (!handle)
255                 return;
256
257         priv->handle = handle;
258         priv->eos = FALSE;
259         priv->position = 0;
260         gnome_vfs_seek (handle, GNOME_VFS_SEEK_CURRENT, priv->position);
261
262         return;
263 }
264
265 /**
266  * tny_vfs_stream_new:
267  * @handle: The #GnomeVFSHandle to write to or read from
268  *
269  * Create an adaptor instance between #TnyStream and #GnomeVFSHandle
270  *
271  * Return value: a new #TnyStream instance
272  **/
273 TnyStream*
274 tny_vfs_stream_new (GnomeVFSHandle *handle)
275 {
276         TnyVfsStream *self = g_object_new (TNY_TYPE_VFS_STREAM, NULL);
277
278         tny_vfs_stream_set_handle (self, handle);
279
280         return TNY_STREAM (self);
281 }
282
283 static void
284 tny_vfs_stream_instance_init (GTypeInstance *instance, gpointer g_class)
285 {
286         TnyVfsStream *self = (TnyVfsStream *)instance;
287         TnyVfsStreamPriv *priv = TNY_VFS_STREAM_GET_PRIVATE (self);
288
289         priv->eos = FALSE;
290         priv->handle = NULL;
291         priv->bound_start = 0;
292         priv->bound_end = (~0);
293         priv->position = 0;
294
295         return;
296 }
297
298 static void
299 tny_vfs_stream_finalize (GObject *object)
300 {
301         TnyVfsStream *self = (TnyVfsStream *)object;   
302         TnyVfsStreamPriv *priv = TNY_VFS_STREAM_GET_PRIVATE (self);
303
304         if (G_LIKELY (priv->handle))
305                 gnome_vfs_close (priv->handle);
306
307         (*parent_class->finalize) (object);
308
309         return;
310 }
311
312 static gint
313 tny_vfs_flush (TnyStream *self)
314 {
315         return 0;
316 }
317
318 static gboolean
319 tny_vfs_is_eos (TnyStream *self)
320 {
321         TnyVfsStreamPriv *priv = TNY_VFS_STREAM_GET_PRIVATE (self);
322
323         return priv->eos;
324 }
325
326 static gint
327 tny_vfs_reset (TnyStream *self)
328 {
329         TnyVfsStreamPriv *priv = TNY_VFS_STREAM_GET_PRIVATE (self);
330         gint retval = 0;
331         GnomeVFSResult res;
332
333         if (priv->handle == NULL)
334         {
335                 errno = EINVAL;
336                 return -1;
337         }
338
339         res = gnome_vfs_seek (priv->handle, GNOME_VFS_SEEK_START, 0);
340
341         if (res == GNOME_VFS_OK) {
342                 priv->position = 0;
343         } else {
344                 tny_vfs_stream_set_errno (res);
345                 retval = -1;
346         }
347         priv->eos = FALSE;
348
349         return retval;
350 }
351
352
353
354 static off_t
355 tny_vfs_seek (TnySeekable *self, off_t offset, int policy)
356 {
357         TnyVfsStreamPriv *priv = TNY_VFS_STREAM_GET_PRIVATE (self);
358         GnomeVFSFileSize real = 0;
359         GnomeVFSResult result;
360         GnomeVFSHandle *handle = priv->handle;
361
362         switch (policy) {
363         case SEEK_SET:
364                 real = offset;
365                 break;
366         case SEEK_CUR:
367                 real = priv->position + offset;
368                 break;
369         case SEEK_END:
370                 if (priv->bound_end == (~0)) {
371                         result = gnome_vfs_seek (handle, GNOME_VFS_SEEK_END, offset);
372                         if (result != GNOME_VFS_OK)
373                                 return -1;
374                         gnome_vfs_tell (handle, &real);
375                         if (real != -1) {
376                                 if (real<priv->bound_start)
377                                         real = priv->bound_start;
378                                 priv->position = real;
379                         }
380                         return real;
381                 }
382                 real = priv->bound_end + offset;
383                 break;
384         }
385
386         if (priv->bound_end != (~0))
387                 real = MIN (real, priv->bound_end);
388         real = MAX (real, priv->bound_start);
389
390         result = gnome_vfs_seek (handle, GNOME_VFS_SEEK_START, real);
391         if (result != GNOME_VFS_OK)
392                 return -1;
393
394         if (real != priv->position && priv->eos)
395                 priv->eos = FALSE;
396
397         priv->position = real;
398
399         return real;
400 }
401
402 static off_t
403 tny_vfs_tell (TnySeekable *self)
404 {
405         TnyVfsStreamPriv *priv = TNY_VFS_STREAM_GET_PRIVATE (self);
406         return priv->position;
407 }
408
409 static gint
410 tny_vfs_set_bounds (TnySeekable *self, off_t start, off_t end)
411 {
412         TnyVfsStreamPriv *priv = TNY_VFS_STREAM_GET_PRIVATE (self);
413         priv->bound_end = end;
414         priv->bound_start = start;
415         return 0;
416 }
417
418 static void
419 tny_stream_init (gpointer g, gpointer iface_data)
420 {
421         TnyStreamIface *klass = (TnyStreamIface *)g;
422
423         klass->reset= tny_vfs_reset;
424         klass->flush= tny_vfs_flush;
425         klass->is_eos= tny_vfs_is_eos;
426         klass->read= tny_vfs_stream_read;
427         klass->write= tny_vfs_stream_write;
428         klass->close= tny_vfs_stream_close;
429         klass->write_to_stream= tny_vfs_stream_write_to_stream;
430
431         return;
432 }
433
434
435 static void
436 tny_seekable_init (gpointer g, gpointer iface_data)
437 {
438         TnySeekableIface *klass = (TnySeekableIface *)g;
439
440         klass->seek= tny_vfs_seek;
441         klass->tell= tny_vfs_tell;
442         klass->set_bounds= tny_vfs_set_bounds;
443
444         return;
445 }
446
447 static void
448 tny_vfs_stream_class_init (TnyVfsStreamClass *class)
449 {
450         GObjectClass *object_class;
451
452         parent_class = g_type_class_peek_parent (class);
453         object_class = (GObjectClass*) class;
454
455         object_class->finalize = tny_vfs_stream_finalize;
456
457         g_type_class_add_private (object_class, sizeof (TnyVfsStreamPriv));
458
459         return;
460 }
461
462 static gpointer
463 tny_vfs_stream_register_type (gpointer notused)
464 {
465         GType type = 0;
466
467         static const GTypeInfo info =
468                 {
469                         sizeof (TnyVfsStreamClass),
470                         NULL,   /* base_init */
471                         NULL,   /* base_finalize */
472                         (GClassInitFunc) tny_vfs_stream_class_init,   /* class_init */
473                         NULL,   /* class_finalize */
474                         NULL,   /* class_data */
475                         sizeof (TnyVfsStream),
476                         0,      /* n_preallocs */
477                         tny_vfs_stream_instance_init,/* instance_init */
478                         NULL
479                 };
480        
481         static const GInterfaceInfo tny_stream_info =
482                 {
483                         (GInterfaceInitFunc) tny_stream_init, /* interface_init */
484                         NULL,         /* interface_finalize */
485                         NULL          /* interface_data */
486                 };
487        
488         static const GInterfaceInfo tny_seekable_info =
489                 {
490                         (GInterfaceInitFunc) tny_seekable_init, /* interface_init */
491                         NULL,         /* interface_finalize */
492                         NULL          /* interface_data */
493                 };
494        
495         type = g_type_register_static (G_TYPE_OBJECT,
496                                        "TnyVfsStream",
497                                        &info, 0);
498        
499         g_type_add_interface_static (type, TNY_TYPE_STREAM,
500                                      &tny_stream_info);
501        
502         g_type_add_interface_static (type, TNY_TYPE_SEEKABLE,
503                                      &tny_seekable_info);
504        
505         return GUINT_TO_POINTER (type);
506 }
507
508 GType
509 tny_vfs_stream_get_type (void)
510 {
511         static GOnce once = G_ONCE_INIT;
512         g_once (&once, tny_vfs_stream_register_type, NULL);
513         return GPOINTER_TO_UINT (once.retval);
514 }
Note: See TracBrowser for help on using the browser.