Bug #615776 - Drop camel-private.h and offer a public alternative for locks
[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 (C) 1999-2008 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
31 #include <gio/gio.h>
32
33 #include "camel-file-utils.h"
34 #include "camel-operation.h"
35 #include "camel-stream-vfs.h"
36
37 static CamelStreamClass *parent_class = NULL;
38
39
40 static void
41 stream_vfs_finalize (CamelStreamVFS *stream_vfs)
42 {
43         if (stream_vfs->stream)
44                 g_object_unref (stream_vfs->stream);
45 }
46
47 static gssize
48 stream_vfs_read (CamelStream *stream,
49                  gchar *buffer,
50                  gsize n)
51 {
52         CamelStreamVFS *stream_vfs = CAMEL_STREAM_VFS (stream);
53         gssize nread;
54         GError *error = NULL;
55
56         nread = g_input_stream_read (
57                 G_INPUT_STREAM (stream_vfs->stream),
58                 buffer, n, NULL, &error);
59
60         if (nread == 0 || error != NULL)
61                 stream->eos = TRUE;
62
63         if (error) {
64                 g_warning ("%s", error->message);
65                 g_error_free (error);
66         }
67
68         return nread;
69 }
70
71 static gssize
72 stream_vfs_write (CamelStream *stream,
73                   const gchar *buffer,
74                   gsize n)
75 {
76         CamelStreamVFS *stream_vfs = CAMEL_STREAM_VFS (stream);
77         gboolean success;
78         gsize bytes_written;
79         GError *error = NULL;
80
81         success = g_output_stream_write_all (
82                 G_OUTPUT_STREAM (stream_vfs->stream),
83                 buffer, n, &bytes_written, NULL, &error);
84
85         if (error) {
86                 g_warning ("%s", error->message);
87                 g_error_free (error);
88         }
89
90         return success ? bytes_written : -1;
91 }
92
93 static gint
94 stream_vfs_flush (CamelStream *stream)
95 {
96         CamelStreamVFS *stream_vfs = CAMEL_STREAM_VFS (stream);
97         gboolean success;
98         GError *error = NULL;
99
100         success = g_output_stream_flush (
101                 G_OUTPUT_STREAM (stream_vfs->stream), NULL, &error);
102
103         if (error) {
104                 g_warning ("%s", error->message);
105                 g_error_free (error);
106         }
107
108         return success ? 0 : -1;
109 }
110
111 static gint
112 stream_vfs_close (CamelStream *stream)
113 {
114         CamelStreamVFS *stream_vfs = CAMEL_STREAM_VFS (stream);
115         gboolean success;
116         GError *error = NULL;
117
118         if (G_IS_OUTPUT_STREAM (stream_vfs->stream))
119                 success = g_output_stream_close (
120                         G_OUTPUT_STREAM (stream_vfs->stream), NULL, &error);
121         else
122                 success = g_input_stream_close (
123                         G_INPUT_STREAM (stream_vfs->stream), NULL, &error);
124
125         if (error) {
126                 g_warning ("%s", error->message);
127                 g_error_free (error);
128         }
129
130         if (success) {
131                 g_object_unref (stream_vfs->stream);
132                 stream_vfs->stream = NULL;
133         }
134
135         return success ? 0 : -1;
136 }
137
138 static void
139 camel_stream_vfs_class_init (CamelStreamVFSClass *class)
140 {
141         CamelStreamClass *stream_class;
142
143         parent_class = CAMEL_STREAM_CLASS (camel_type_get_global_classfuncs (camel_stream_get_type ()));
144
145         stream_class = CAMEL_STREAM_CLASS (class);
146         stream_class->read = stream_vfs_read;
147         stream_class->write = stream_vfs_write;
148         stream_class->flush = stream_vfs_flush;
149         stream_class->close = stream_vfs_close;
150 }
151
152 static void
153 camel_stream_vfs_init (CamelStreamVFS *stream)
154 {
155         stream->stream = NULL;
156 }
157
158 CamelType
159 camel_stream_vfs_get_type (void)
160 {
161         static CamelType camel_stream_vfs_type = CAMEL_INVALID_TYPE;
162
163         if (camel_stream_vfs_type == CAMEL_INVALID_TYPE) {
164                 camel_stream_vfs_type = camel_type_register (camel_stream_get_type (), "CamelStreamVFS",
165                                                             sizeof (CamelStreamVFS),
166                                                             sizeof (CamelStreamVFSClass),
167                                                             (CamelObjectClassInitFunc) camel_stream_vfs_class_init,
168                                                             NULL,
169                                                             (CamelObjectInitFunc) camel_stream_vfs_init,
170                                                             (CamelObjectFinalizeFunc) stream_vfs_finalize);
171         }
172
173         return camel_stream_vfs_type;
174 }
175
176 /**
177  * camel_stream_vfs_new_with_stream:
178  * @stream: a GInputStream or GOutputStream instance
179  *
180  * Creates a new fs stream using the given gio stream @stream as the
181  * backing store. When the stream is destroyed, the file descriptor
182  * will be closed. This will not increase reference counter on the stream.
183  *
184  * Returns: a new #CamelStreamVFS
185  *
186  * Since: 2.24
187  **/
188 CamelStream *
189 camel_stream_vfs_new_with_stream (GObject *stream)
190 {
191         CamelStreamVFS *stream_vfs;
192
193         errno = EINVAL;
194
195         if (!stream)
196                 return NULL;
197
198         g_return_val_if_fail (G_IS_OUTPUT_STREAM (stream) || G_IS_INPUT_STREAM (stream), NULL);
199
200         errno = 0;
201         stream_vfs = CAMEL_STREAM_VFS (camel_object_new (camel_stream_vfs_get_type ()));
202         stream_vfs->stream = stream;
203
204         return CAMEL_STREAM (stream_vfs);
205 }
206
207 /**
208  * camel_stream_vfs_new_with_uri:
209  * @uri: a file uri
210  * @mode: opening mode for the uri file
211  *
212  * Creates a new #CamelStreamVFS corresponding to the named file and mode.
213  *
214  * Returns: the new stream, or %NULL on error.
215  **/
216 CamelStream *
217 camel_stream_vfs_new_with_uri (const gchar *uri, CamelStreamVFSOpenMethod mode)
218 {
219         GFile *file;
220         GObject *stream;
221         GError *error = NULL;
222
223         file = g_file_new_for_uri (uri);
224
225         switch (mode) {
226                 case CAMEL_STREAM_VFS_CREATE:
227                         stream = G_OBJECT (g_file_replace (file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, &error));
228                         break;
229                 case CAMEL_STREAM_VFS_APPEND:
230                         stream = G_OBJECT (g_file_append_to (file, G_FILE_CREATE_NONE, NULL, &error));
231                         break;
232                 case CAMEL_STREAM_VFS_READ:
233                         stream = G_OBJECT (g_file_read (file, NULL, &error));
234                         break;
235                 default:
236                         errno = EINVAL;
237                         g_return_val_if_reached (NULL);
238         }
239
240         g_object_unref (file);
241
242         if (error) {
243                 errno = error->code;
244                 g_warning ("%s", error->message);
245                 g_error_free (error);
246                 return NULL;
247         }
248
249         return camel_stream_vfs_new_with_stream (stream);
250 }
251
252 /**
253  * camel_stream_vfs_is_writable:
254  * @stream_vfs: a #CamelStreamVFS instance
255  *
256  * Returns: whether is the underlying stream writable or not.
257  *
258  * Since: 2.24
259  **/
260 gboolean
261 camel_stream_vfs_is_writable (CamelStreamVFS *stream_vfs)
262 {
263         g_return_val_if_fail (stream_vfs != NULL, FALSE);
264         g_return_val_if_fail (stream_vfs->stream != NULL, FALSE);
265
266         return G_IS_OUTPUT_STREAM (stream_vfs->stream);
267 }