Extending test-client-custom-summary to try e_book_client_get_contacts_uids()
[platform/upstream/evolution-data-server.git] / camel / camel-stream-fs.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* camel-stream-fs.c : file system based stream */
3
4 /*
5  * Authors: Bertrand Guiheneuf <bertrand@helixcode.com>
6  *          Michael Zucchi <notzed@ximian.com>
7  *
8  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of version 2 of the GNU Lesser General Public
12  * License as published by the Free Software Foundation.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
22  * USA
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <errno.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <sys/stat.h>
33 #include <sys/types.h>
34
35 #include <glib/gstdio.h>
36
37 #include "camel-file-utils.h"
38 #include "camel-operation.h"
39 #include "camel-stream-fs.h"
40 #include "camel-win32.h"
41
42 #define CAMEL_STREAM_FS_GET_PRIVATE(obj) \
43         (G_TYPE_INSTANCE_GET_PRIVATE \
44         ((obj), CAMEL_TYPE_STREAM_FS, CamelStreamFsPrivate))
45
46 struct _CamelStreamFsPrivate {
47         gint fd;        /* file descriptor on the underlying file */
48 };
49
50 /* Forward Declarations */
51 static void camel_stream_fs_seekable_init (GSeekableIface *interface);
52
53 G_DEFINE_TYPE_WITH_CODE (
54         CamelStreamFs, camel_stream_fs, CAMEL_TYPE_STREAM,
55         G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE, camel_stream_fs_seekable_init))
56
57 static void
58 stream_fs_finalize (GObject *object)
59 {
60         CamelStreamFsPrivate *priv;
61
62         priv = CAMEL_STREAM_FS_GET_PRIVATE (object);
63
64         if (priv->fd != -1)
65                 close (priv->fd);
66
67         /* Chain up to parent's finalize() method. */
68         G_OBJECT_CLASS (camel_stream_fs_parent_class)->finalize (object);
69 }
70
71 static gssize
72 stream_fs_read (CamelStream *stream,
73                 gchar *buffer,
74                 gsize n,
75                 GCancellable *cancellable,
76                 GError **error)
77 {
78         CamelStreamFsPrivate *priv;
79         gssize nread;
80
81         priv = CAMEL_STREAM_FS_GET_PRIVATE (stream);
82
83         nread = camel_read (priv->fd, buffer, n, cancellable, error);
84
85         if (nread == 0)
86                 stream->eos = TRUE;
87
88         return nread;
89 }
90
91 static gssize
92 stream_fs_write (CamelStream *stream,
93                  const gchar *buffer,
94                  gsize n,
95                  GCancellable *cancellable,
96                  GError **error)
97 {
98         CamelStreamFsPrivate *priv;
99
100         priv = CAMEL_STREAM_FS_GET_PRIVATE (stream);
101
102         return camel_write (priv->fd, buffer, n, cancellable, error);
103 }
104
105 static gint
106 stream_fs_flush (CamelStream *stream,
107                  GCancellable *cancellable,
108                  GError **error)
109 {
110         CamelStreamFsPrivate *priv;
111
112         priv = CAMEL_STREAM_FS_GET_PRIVATE (stream);
113
114         if (g_cancellable_set_error_if_cancelled (cancellable, error))
115                 return -1;
116
117         if (fsync (priv->fd) == -1) {
118                 g_set_error (
119                         error, G_IO_ERROR,
120                         g_io_error_from_errno (errno),
121                         "%s", g_strerror (errno));
122                 return -1;
123         }
124
125         return 0;
126 }
127
128 static gint
129 stream_fs_close (CamelStream *stream,
130                  GCancellable *cancellable,
131                  GError **error)
132 {
133         CamelStreamFsPrivate *priv;
134
135         priv = CAMEL_STREAM_FS_GET_PRIVATE (stream);
136
137         if (g_cancellable_set_error_if_cancelled (cancellable, error))
138                 return -1;
139
140         if (close (priv->fd) == -1) {
141                 g_set_error (
142                         error, G_IO_ERROR,
143                         g_io_error_from_errno (errno),
144                         "%s", g_strerror (errno));
145                 return -1;
146         }
147
148         priv->fd = -1;
149
150         return 0;
151 }
152
153 static goffset
154 stream_fs_tell (GSeekable *seekable)
155 {
156         CamelStreamFsPrivate *priv;
157
158         priv = CAMEL_STREAM_FS_GET_PRIVATE (seekable);
159
160         return (goffset) lseek (priv->fd, 0, SEEK_CUR);
161 }
162
163 static gboolean
164 stream_fs_can_seek (GSeekable *seekable)
165 {
166         return TRUE;
167 }
168
169 static gboolean
170 stream_fs_seek (GSeekable *seekable,
171                 goffset offset,
172                 GSeekType type,
173                 GCancellable *cancellable,
174                 GError **error)
175 {
176         CamelStreamFsPrivate *priv;
177         goffset real = 0;
178
179         priv = CAMEL_STREAM_FS_GET_PRIVATE (seekable);
180
181         switch (type) {
182         case G_SEEK_SET:
183                 real = offset;
184                 break;
185         case G_SEEK_CUR:
186                 real = g_seekable_tell (seekable) + offset;
187                 break;
188         case G_SEEK_END:
189                 real = lseek (priv->fd, offset, SEEK_END);
190                 if (real == -1) {
191                         g_set_error (
192                                 error, G_IO_ERROR,
193                                 g_io_error_from_errno (errno),
194                                 "%s", g_strerror (errno));
195                         return FALSE;
196                 }
197                 return TRUE;
198         }
199
200         real = lseek (priv->fd, real, SEEK_SET);
201         if (real == -1) {
202                 g_set_error (
203                         error, G_IO_ERROR,
204                         g_io_error_from_errno (errno),
205                         "%s", g_strerror (errno));
206                 return FALSE;
207         }
208
209         CAMEL_STREAM (seekable)->eos = FALSE;
210
211         return TRUE;
212 }
213
214 static gboolean
215 stream_fs_can_truncate (GSeekable *seekable)
216 {
217         return FALSE;
218 }
219
220 static gboolean
221 stream_fs_truncate_fn (GSeekable *seekable,
222                        goffset offset,
223                        GCancellable *cancellable,
224                        GError **error)
225 {
226         /* XXX Don't bother translating this.  Camel never calls it. */
227         g_set_error (
228                 error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
229                 "Truncation is not supported");
230
231         return FALSE;
232 }
233
234 static void
235 camel_stream_fs_class_init (CamelStreamFsClass *class)
236 {
237         GObjectClass *object_class;
238         CamelStreamClass *stream_class;
239
240         g_type_class_add_private (class, sizeof (CamelStreamFsPrivate));
241
242         object_class = G_OBJECT_CLASS (class);
243         object_class->finalize = stream_fs_finalize;
244
245         stream_class = CAMEL_STREAM_CLASS (class);
246         stream_class->read = stream_fs_read;
247         stream_class->write = stream_fs_write;
248         stream_class->flush = stream_fs_flush;
249         stream_class->close = stream_fs_close;
250 }
251
252 static void
253 camel_stream_fs_seekable_init (GSeekableIface *interface)
254 {
255         interface->tell = stream_fs_tell;
256         interface->can_seek = stream_fs_can_seek;
257         interface->seek = stream_fs_seek;
258         interface->can_truncate = stream_fs_can_truncate;
259         interface->truncate_fn = stream_fs_truncate_fn;
260 }
261
262 static void
263 camel_stream_fs_init (CamelStreamFs *stream)
264 {
265         stream->priv = CAMEL_STREAM_FS_GET_PRIVATE (stream);
266         stream->priv->fd = -1;
267 }
268
269 /**
270  * camel_stream_fs_new_with_fd:
271  * @fd: a file descriptor
272  *
273  * Creates a new fs stream using the given file descriptor @fd as the
274  * backing store. When the stream is destroyed, the file descriptor
275  * will be closed.
276  *
277  * Returns: a new #CamelStreamFs
278  **/
279 CamelStream *
280 camel_stream_fs_new_with_fd (gint fd)
281 {
282         CamelStreamFsPrivate *priv;
283         CamelStream *stream;
284
285         if (fd == -1)
286                 return NULL;
287
288         stream = g_object_new (CAMEL_TYPE_STREAM_FS, NULL);
289         priv = CAMEL_STREAM_FS_GET_PRIVATE (stream);
290
291         priv->fd = fd;
292
293         return stream;
294 }
295
296 /**
297  * camel_stream_fs_new_with_name:
298  * @name: a local filename
299  * @flags: flags as in open(2)
300  * @mode: a file mode
301  * @error: return location for a #GError, or %NULL
302  *
303  * Creates a new #CamelStreamFs corresponding to the named file, flags,
304  * and mode.
305  *
306  * Returns: the new stream, or %NULL on error.
307  **/
308 CamelStream *
309 camel_stream_fs_new_with_name (const gchar *name,
310                                gint flags,
311                                mode_t mode,
312                                GError **error)
313 {
314         gint fd;
315
316         fd = g_open (name, flags | O_BINARY, mode);
317         if (fd == -1) {
318                 g_set_error (
319                         error, G_IO_ERROR,
320                         g_io_error_from_errno (errno),
321                         "%s", g_strerror (errno));
322                 return NULL;
323         }
324
325         return camel_stream_fs_new_with_fd (fd);
326 }
327
328 /**
329  * camel_stream_fs_get_fd:
330  * @stream: a #CamelStream
331  *
332  * Since: 2.32
333  **/
334 gint
335 camel_stream_fs_get_fd (CamelStreamFs *stream)
336 {
337         g_return_val_if_fail (CAMEL_IS_STREAM_FS (stream), -1);
338
339         return stream->priv->fd;
340 }