Fix FSF address (Tobias Mueller, #470445)
[platform/upstream/evolution-data-server.git] / camel / camel-stream-vfs.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* camel-stream-vfs.c : file system based stream */
3
4 /*
5  * Authors: Srinivasa Ragavan <sragavan@novell.com>
6  *
7  * Copyright 2006 Novell, Inc. (www.novell.com)
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of version 2 of the GNU Lesser General Public
11  * License as published by the Free Software Foundation.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
21  * USA
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <errno.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <sys/stat.h>
32 #include <sys/types.h>
33
34 #include <glib.h>
35 #include <glib/gstdio.h>
36
37 #include "camel-file-utils.h"
38 #include "camel-operation.h"
39 #include "camel-private.h"
40 #include "camel-stream-vfs.h"
41
42 static CamelSeekableStreamClass *parent_class = NULL;
43
44 /* Returns the class for a CamelStreamVFS */
45 #define CSVFS_CLASS(so) CAMEL_STREAM_VFS_CLASS (CAMEL_OBJECT_GET_CLASS(so))
46
47 static ssize_t stream_read   (CamelStream *stream, char *buffer, size_t n);
48 static ssize_t stream_write  (CamelStream *stream, const char *buffer, size_t n);
49 /* static int stream_flush  (CamelStream *stream); */
50 static int stream_close  (CamelStream *stream);
51 static off_t stream_seek (CamelSeekableStream *stream, off_t offset,
52                           CamelStreamSeekPolicy policy);
53
54 static void
55 camel_stream_vfs_class_init (CamelStreamVFSClass *camel_stream_vfs_class)
56 {
57         CamelSeekableStreamClass *camel_seekable_stream_class =
58                 CAMEL_SEEKABLE_STREAM_CLASS (camel_stream_vfs_class);
59         CamelStreamClass *camel_stream_class =
60                 CAMEL_STREAM_CLASS (camel_stream_vfs_class);
61
62         parent_class = CAMEL_SEEKABLE_STREAM_CLASS (camel_type_get_global_classfuncs (camel_seekable_stream_get_type ()));
63
64         /* virtual method overload */
65         camel_stream_class->read = stream_read;
66         camel_stream_class->write = stream_write;
67 /*      camel_stream_class->flush = stream_flush; */
68         camel_stream_class->close = stream_close;
69
70         camel_seekable_stream_class->seek = stream_seek;
71 }
72
73 static void
74 camel_stream_vfs_init (gpointer object, gpointer klass)
75 {
76         CamelStreamVFS *stream = CAMEL_STREAM_VFS (object);
77
78         stream->handle = GINT_TO_POINTER (-1);
79         ((CamelSeekableStream *)stream)->bound_end = CAMEL_STREAM_UNBOUND;
80 }
81
82 static void
83 camel_stream_vfs_finalize (CamelObject *object)
84 {
85         CamelStreamVFS *stream_vfs = CAMEL_STREAM_VFS (object);
86
87         if (stream_vfs->handle != GINT_TO_POINTER (-1))
88                 gnome_vfs_close (stream_vfs->handle);
89 }
90
91
92 CamelType
93 camel_stream_vfs_get_type (void)
94 {
95         static CamelType camel_stream_vfs_type = CAMEL_INVALID_TYPE;
96
97         if (camel_stream_vfs_type == CAMEL_INVALID_TYPE) {
98                 camel_stream_vfs_type = camel_type_register (camel_seekable_stream_get_type (), "CamelStreamVFS",
99                                                             sizeof (CamelStreamVFS),
100                                                             sizeof (CamelStreamVFSClass),
101                                                             (CamelObjectClassInitFunc) camel_stream_vfs_class_init,
102                                                             NULL,
103                                                             (CamelObjectInitFunc) camel_stream_vfs_init,
104                                                             (CamelObjectFinalizeFunc) camel_stream_vfs_finalize);
105         }
106
107         return camel_stream_vfs_type;
108 }
109
110 /**
111  * camel_stream_vfs_new_with_handle:
112  * @handle: a GnomeVFS handle
113  *
114  * Creates a new fs stream using the given GnomeVFS handle @handle as the
115  * backing store. When the stream is destroyed, the file descriptor
116  * will be closed.
117  *
118  * Returns a new #CamelStreamVFS
119  **/
120 CamelStream *
121 camel_stream_vfs_new_with_handle (GnomeVFSHandle *handle)
122 {
123         CamelStreamVFS *stream_vfs;
124         off_t offset;
125         
126         if (!handle)
127                 return NULL;
128
129         stream_vfs = CAMEL_STREAM_VFS (camel_object_new (camel_stream_vfs_get_type ()));
130         stream_vfs->handle = handle;
131         gnome_vfs_seek (handle, GNOME_VFS_SEEK_CURRENT, 0);
132         offset = 0;
133         CAMEL_SEEKABLE_STREAM (stream_vfs)->position = offset;
134
135         return CAMEL_STREAM (stream_vfs);
136 }
137
138 /**
139  * camel_stream_vfs_new_with_uri:
140  * @name: a file uri
141  * @flags: flags as in open(2)
142  * @mode: a file mode
143  *
144  * Creates a new #CamelStreamVFS corresponding to the named file, flags,
145  * and mode.
146  *
147  * Returns the new stream, or %NULL on error.
148  **/
149 CamelStream *
150 camel_stream_vfs_new_with_uri (const char *name, int flags, mode_t mode)
151 {
152         GnomeVFSResult result;
153         GnomeVFSHandle *handle;
154         int vfs_flag = 0;
155         
156         if (flags & O_WRONLY)
157                 vfs_flag = vfs_flag | GNOME_VFS_OPEN_WRITE;
158         if (flags & O_RDONLY)
159                 vfs_flag = vfs_flag | GNOME_VFS_OPEN_READ;
160         if (flags & O_RDWR)
161                 vfs_flag = vfs_flag | GNOME_VFS_OPEN_READ |GNOME_VFS_OPEN_WRITE;
162         
163         if (flags & O_CREAT)
164                 result = gnome_vfs_create (&handle, name, vfs_flag, FALSE, mode);
165         else
166                 result = gnome_vfs_open (&handle, name, vfs_flag);
167         
168         if (result != GNOME_VFS_OK) {
169                 return NULL;
170         }
171
172         return camel_stream_vfs_new_with_handle (handle);
173 }
174
175 static ssize_t
176 stream_read (CamelStream *stream, char *buffer, size_t n)
177 {
178         CamelStreamVFS *stream_vfs = CAMEL_STREAM_VFS (stream);
179         CamelSeekableStream *seekable = CAMEL_SEEKABLE_STREAM (stream);
180         GnomeVFSFileSize nread = 0;
181         GnomeVFSResult result;
182         
183         if (seekable->bound_end != CAMEL_STREAM_UNBOUND)
184                 n = MIN (seekable->bound_end - seekable->position, n);
185
186         result = gnome_vfs_read (stream_vfs->handle, buffer, n, &nread);
187         
188         if (nread > 0 && result == GNOME_VFS_OK)
189                 seekable->position += nread;
190         else if (nread == 0)
191                 stream->eos = TRUE;
192         
193         return nread;
194 }
195
196 static ssize_t
197 stream_write (CamelStream *stream, const char *buffer, size_t n)
198 {
199         CamelStreamVFS *stream_vfs = CAMEL_STREAM_VFS (stream);
200         CamelSeekableStream *seekable = CAMEL_SEEKABLE_STREAM (stream);
201         GnomeVFSFileSize nwritten = 0;
202         GnomeVFSResult result;
203         
204         if (seekable->bound_end != CAMEL_STREAM_UNBOUND)
205                 n = MIN (seekable->bound_end - seekable->position, n);
206
207         result = gnome_vfs_write (stream_vfs->handle, buffer, n, &nwritten);
208         
209         if (nwritten > 0 && result == GNOME_VFS_OK)
210                 seekable->position += nwritten;
211         
212         return nwritten;
213 }
214
215 /* static int */
216 /* stream_flush (CamelStream *stream) */
217 /* { */
218 /*      return fsync(((CamelStreamVFS *)stream)->handle); */
219 /* } */
220
221 static int
222 stream_close (CamelStream *stream)
223 {
224         GnomeVFSResult result;
225
226         result = gnome_vfs_close(((CamelStreamVFS *)stream)->handle);
227         
228         if (result != GNOME_VFS_OK)
229                 return -1;
230         
231         ((CamelStreamVFS *)stream)->handle = NULL;
232         return 0;
233 }
234
235 static off_t
236 stream_seek (CamelSeekableStream *stream, off_t offset, CamelStreamSeekPolicy policy)
237 {
238         CamelStreamVFS *stream_vfs = CAMEL_STREAM_VFS (stream);
239         GnomeVFSFileSize real = 0;
240         GnomeVFSResult result;
241         GnomeVFSHandle *handle = stream_vfs->handle;
242         
243         switch (policy) {
244         case CAMEL_STREAM_SET:
245                 real = offset;
246                 break;
247         case CAMEL_STREAM_CUR:
248                 real = stream->position + offset;
249                 break;
250         case CAMEL_STREAM_END:
251                 if (stream->bound_end == CAMEL_STREAM_UNBOUND) {
252                         result = gnome_vfs_seek (handle, GNOME_VFS_SEEK_END, offset);
253                         if (result != GNOME_VFS_OK)
254                                 return -1;
255                         gnome_vfs_tell (handle, &real);
256                         if (real != -1) {
257                                 if (real<stream->bound_start)
258                                         real = stream->bound_start;
259                                 stream->position = real;
260                         }
261                         return real;
262                 }
263                 real = stream->bound_end + offset;
264                 break;
265         }
266
267         if (stream->bound_end != CAMEL_STREAM_UNBOUND)
268                 real = MIN (real, stream->bound_end);
269         real = MAX (real, stream->bound_start);
270
271         result = gnome_vfs_seek (handle, GNOME_VFS_SEEK_START, real);
272         if (result != GNOME_VFS_OK)
273                 return -1;
274
275         if (real != stream->position && ((CamelStream *)stream)->eos)
276                 ((CamelStream *)stream)->eos = FALSE;
277
278         stream->position = real;
279
280         return real;
281 }