1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* camel-stream-fs.c : file system based stream */
5 * Authors: Bertrand Guiheneuf <bertrand@helixcode.com>
6 * Michael Zucchi <notzed@ximian.com>
8 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
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.
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.
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
33 #include <sys/types.h>
35 #include <glib/gstdio.h>
37 #include "camel-file-utils.h"
38 #include "camel-operation.h"
39 #include "camel-stream-fs.h"
40 #include "camel-win32.h"
42 #define CAMEL_STREAM_FS_GET_PRIVATE(obj) \
43 (G_TYPE_INSTANCE_GET_PRIVATE \
44 ((obj), CAMEL_TYPE_STREAM_FS, CamelStreamFsPrivate))
46 struct _CamelStreamFsPrivate {
47 gint fd; /* file descriptor on the underlying file */
50 /* Forward Declarations */
51 static void camel_stream_fs_seekable_init (GSeekableIface *interface);
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))
58 stream_fs_finalize (GObject *object)
60 CamelStreamFsPrivate *priv;
62 priv = CAMEL_STREAM_FS_GET_PRIVATE (object);
67 /* Chain up to parent's finalize() method. */
68 G_OBJECT_CLASS (camel_stream_fs_parent_class)->finalize (object);
72 stream_fs_read (CamelStream *stream,
75 GCancellable *cancellable,
78 CamelStreamFsPrivate *priv;
81 priv = CAMEL_STREAM_FS_GET_PRIVATE (stream);
83 nread = camel_read (priv->fd, buffer, n, cancellable, error);
92 stream_fs_write (CamelStream *stream,
95 GCancellable *cancellable,
98 CamelStreamFsPrivate *priv;
100 priv = CAMEL_STREAM_FS_GET_PRIVATE (stream);
102 return camel_write (priv->fd, buffer, n, cancellable, error);
106 stream_fs_flush (CamelStream *stream,
107 GCancellable *cancellable,
110 CamelStreamFsPrivate *priv;
112 priv = CAMEL_STREAM_FS_GET_PRIVATE (stream);
114 if (g_cancellable_set_error_if_cancelled (cancellable, error))
117 if (fsync (priv->fd) == -1) {
120 g_io_error_from_errno (errno),
121 "%s", g_strerror (errno));
129 stream_fs_close (CamelStream *stream,
130 GCancellable *cancellable,
133 CamelStreamFsPrivate *priv;
135 priv = CAMEL_STREAM_FS_GET_PRIVATE (stream);
137 if (g_cancellable_set_error_if_cancelled (cancellable, error))
140 if (close (priv->fd) == -1) {
143 g_io_error_from_errno (errno),
144 "%s", g_strerror (errno));
154 stream_fs_tell (GSeekable *seekable)
156 CamelStreamFsPrivate *priv;
158 priv = CAMEL_STREAM_FS_GET_PRIVATE (seekable);
160 return (goffset) lseek (priv->fd, 0, SEEK_CUR);
164 stream_fs_can_seek (GSeekable *seekable)
170 stream_fs_seek (GSeekable *seekable,
173 GCancellable *cancellable,
176 CamelStreamFsPrivate *priv;
179 priv = CAMEL_STREAM_FS_GET_PRIVATE (seekable);
186 real = g_seekable_tell (seekable) + offset;
189 real = lseek (priv->fd, offset, SEEK_END);
193 g_io_error_from_errno (errno),
194 "%s", g_strerror (errno));
200 real = lseek (priv->fd, real, SEEK_SET);
204 g_io_error_from_errno (errno),
205 "%s", g_strerror (errno));
209 CAMEL_STREAM (seekable)->eos = FALSE;
215 stream_fs_can_truncate (GSeekable *seekable)
221 stream_fs_truncate_fn (GSeekable *seekable,
223 GCancellable *cancellable,
226 /* XXX Don't bother translating this. Camel never calls it. */
228 error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
229 "Truncation is not supported");
235 camel_stream_fs_class_init (CamelStreamFsClass *class)
237 GObjectClass *object_class;
238 CamelStreamClass *stream_class;
240 g_type_class_add_private (class, sizeof (CamelStreamFsPrivate));
242 object_class = G_OBJECT_CLASS (class);
243 object_class->finalize = stream_fs_finalize;
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;
253 camel_stream_fs_seekable_init (GSeekableIface *interface)
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;
263 camel_stream_fs_init (CamelStreamFs *stream)
265 stream->priv = CAMEL_STREAM_FS_GET_PRIVATE (stream);
266 stream->priv->fd = -1;
270 * camel_stream_fs_new_with_fd:
271 * @fd: a file descriptor
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
277 * Returns: a new #CamelStreamFs
280 camel_stream_fs_new_with_fd (gint fd)
282 CamelStreamFsPrivate *priv;
288 stream = g_object_new (CAMEL_TYPE_STREAM_FS, NULL);
289 priv = CAMEL_STREAM_FS_GET_PRIVATE (stream);
297 * camel_stream_fs_new_with_name:
298 * @name: a local filename
299 * @flags: flags as in open(2)
301 * @error: return location for a #GError, or %NULL
303 * Creates a new #CamelStreamFs corresponding to the named file, flags,
306 * Returns: the new stream, or %NULL on error.
309 camel_stream_fs_new_with_name (const gchar *name,
316 fd = g_open (name, flags | O_BINARY, mode);
320 g_io_error_from_errno (errno),
321 "%s", g_strerror (errno));
325 return camel_stream_fs_new_with_fd (fd);
329 * camel_stream_fs_get_fd:
330 * @stream: a #CamelStream
335 camel_stream_fs_get_fd (CamelStreamFs *stream)
337 g_return_val_if_fail (CAMEL_IS_STREAM_FS (stream), -1);
339 return stream->priv->fd;