1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*  GMime
3  *  Copyright (C) 2000-2014 Jeffrey Stedfast
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Lesser General Public License
7  *  as published by the Free Software Foundation; either version 2.1
8  *  of the License, or (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public
16  *  License along with this library; if not, write to the Free
17  *  Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
18  *  02110-1301, USA.
19  */
20 
21 
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 
26 #include <glib.h>
27 
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include <errno.h>
33 
34 #include "gmime-stream-pipe.h"
35 
36 
37 /**
38  * SECTION: gmime-stream-pipe
39  * @title: GMimeStreamPipe
40  * @short_description: A low-level pipe stream
41  * @see_also: #GMimeStream
42  *
43  * A simple #GMimeStream implementation that sits on top of low-level
44  * POSIX pipes.
45  **/
46 
47 
48 static void g_mime_stream_pipe_class_init (GMimeStreamPipeClass *klass);
49 static void g_mime_stream_pipe_init (GMimeStreamPipe *stream, GMimeStreamPipeClass *klass);
50 static void g_mime_stream_pipe_finalize (GObject *object);
51 
52 static ssize_t stream_read (GMimeStream *stream, char *buf, size_t len);
53 static ssize_t stream_write (GMimeStream *stream, const char *buf, size_t len);
54 static int stream_flush (GMimeStream *stream);
55 static int stream_close (GMimeStream *stream);
56 static gboolean stream_eos (GMimeStream *stream);
57 static int stream_reset (GMimeStream *stream);
58 static gint64 stream_seek (GMimeStream *stream, gint64 offset, GMimeSeekWhence whence);
59 static gint64 stream_tell (GMimeStream *stream);
60 static gint64 stream_length (GMimeStream *stream);
61 static GMimeStream *stream_substream (GMimeStream *stream, gint64 start, gint64 end);
62 
63 
64 static GMimeStreamClass *parent_class = NULL;
65 
66 
67 GType
g_mime_stream_pipe_get_type(void)68 g_mime_stream_pipe_get_type (void)
69 {
70 	static GType type = 0;
71 
72 	if (!type) {
73 		static const GTypeInfo info = {
74 			sizeof (GMimeStreamPipeClass),
75 			NULL, /* base_class_init */
76 			NULL, /* base_class_finalize */
77 			(GClassInitFunc) g_mime_stream_pipe_class_init,
78 			NULL, /* class_finalize */
79 			NULL, /* class_data */
80 			sizeof (GMimeStreamPipe),
81 			0,    /* n_preallocs */
82 			(GInstanceInitFunc) g_mime_stream_pipe_init,
83 		};
84 
85 		type = g_type_register_static (GMIME_TYPE_STREAM, "GMimeStreamPipe", &info, 0);
86 	}
87 
88 	return type;
89 }
90 
91 
92 static void
g_mime_stream_pipe_class_init(GMimeStreamPipeClass * klass)93 g_mime_stream_pipe_class_init (GMimeStreamPipeClass *klass)
94 {
95 	GMimeStreamClass *stream_class = GMIME_STREAM_CLASS (klass);
96 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
97 
98 	parent_class = g_type_class_ref (GMIME_TYPE_STREAM);
99 
100 	object_class->finalize = g_mime_stream_pipe_finalize;
101 
102 	stream_class->read = stream_read;
103 	stream_class->write = stream_write;
104 	stream_class->flush = stream_flush;
105 	stream_class->close = stream_close;
106 	stream_class->eos = stream_eos;
107 	stream_class->reset = stream_reset;
108 	stream_class->seek = stream_seek;
109 	stream_class->tell = stream_tell;
110 	stream_class->length = stream_length;
111 	stream_class->substream = stream_substream;
112 }
113 
114 static void
g_mime_stream_pipe_init(GMimeStreamPipe * stream,GMimeStreamPipeClass * klass)115 g_mime_stream_pipe_init (GMimeStreamPipe *stream, GMimeStreamPipeClass *klass)
116 {
117 	stream->owner = TRUE;
118 	stream->eos = FALSE;
119 	stream->fd = -1;
120 }
121 
122 static void
g_mime_stream_pipe_finalize(GObject * object)123 g_mime_stream_pipe_finalize (GObject *object)
124 {
125 	GMimeStreamPipe *stream = (GMimeStreamPipe *) object;
126 
127 	if (stream->owner && stream->fd != -1)
128 		close (stream->fd);
129 
130 	G_OBJECT_CLASS (parent_class)->finalize (object);
131 }
132 
133 static ssize_t
stream_read(GMimeStream * stream,char * buf,size_t len)134 stream_read (GMimeStream *stream, char *buf, size_t len)
135 {
136 	GMimeStreamPipe *pipes = (GMimeStreamPipe *) stream;
137 	ssize_t nread;
138 
139 	if (pipes->fd == -1) {
140 		errno = EBADF;
141 		return -1;
142 	}
143 
144 	if (stream->bound_end != -1 && stream->position >= stream->bound_end) {
145 		errno = EINVAL;
146 		return -1;
147 	}
148 
149 	if (stream->bound_end != -1)
150 		len = (size_t) MIN (stream->bound_end - stream->position, (gint64) len);
151 
152 	do {
153 		nread = read (pipes->fd, buf, len);
154 	} while (nread == -1 && errno == EINTR);
155 
156 	if (nread > 0) {
157 		stream->position += nread;
158 	} else if (nread == 0) {
159 		pipes->eos = TRUE;
160 	}
161 
162 	return nread;
163 }
164 
165 static ssize_t
stream_write(GMimeStream * stream,const char * buf,size_t len)166 stream_write (GMimeStream *stream, const char *buf, size_t len)
167 {
168 	GMimeStreamPipe *pipes = (GMimeStreamPipe *) stream;
169 	size_t nwritten = 0;
170 	ssize_t n;
171 
172 	if (pipes->fd == -1) {
173 		errno = EBADF;
174 		return -1;
175 	}
176 
177 	if (stream->bound_end != -1 && stream->position >= stream->bound_end) {
178 		errno = EINVAL;
179 		return -1;
180 	}
181 
182 	if (stream->bound_end != -1)
183 		len = (size_t) MIN (stream->bound_end - stream->position, (gint64) len);
184 
185 	do {
186 		do {
187 			n = write (pipes->fd, buf + nwritten, len - nwritten);
188 		} while (n == -1 && (errno == EINTR || errno == EAGAIN));
189 
190 		if (n > 0)
191 			nwritten += n;
192 	} while (n != -1 && nwritten < len);
193 
194 	if (n == -1 && (errno == EFBIG || errno == ENOSPC))
195 		pipes->eos = TRUE;
196 
197 	if (nwritten > 0) {
198 		stream->position += nwritten;
199 	} else if (n == -1) {
200 		/* error and nothing written */
201 		return -1;
202 	}
203 
204 	return nwritten;
205 }
206 
207 static int
stream_flush(GMimeStream * stream)208 stream_flush (GMimeStream *stream)
209 {
210 	GMimeStreamPipe *pipes = (GMimeStreamPipe *) stream;
211 
212 	if (pipes->fd == -1) {
213 		errno = EBADF;
214 		return -1;
215 	}
216 
217 	return 0;
218 }
219 
220 static int
stream_close(GMimeStream * stream)221 stream_close (GMimeStream *stream)
222 {
223 	GMimeStreamPipe *pipes = (GMimeStreamPipe *) stream;
224 	int rv;
225 
226 	if (pipes->fd == -1)
227 		return 0;
228 
229 	do {
230 		if ((rv = close (pipes->fd)) == 0)
231 			pipes->fd = -1;
232 	} while (rv == -1 && errno == EINTR);
233 
234 	return rv;
235 }
236 
237 static gboolean
stream_eos(GMimeStream * stream)238 stream_eos (GMimeStream *stream)
239 {
240 	GMimeStreamPipe *pipes = (GMimeStreamPipe *) stream;
241 
242 	if (pipes->fd == -1)
243 		return TRUE;
244 
245 	return pipes->eos;
246 }
247 
248 static int
stream_reset(GMimeStream * stream)249 stream_reset (GMimeStream *stream)
250 {
251 	GMimeStreamPipe *pipes = (GMimeStreamPipe *) stream;
252 
253 	if (pipes->fd == -1) {
254 		errno = EBADF;
255 		return -1;
256 	}
257 
258 	return 0;
259 }
260 
261 static gint64
stream_seek(GMimeStream * stream,gint64 offset,GMimeSeekWhence whence)262 stream_seek (GMimeStream *stream, gint64 offset, GMimeSeekWhence whence)
263 {
264 	return -1;
265 }
266 
267 static gint64
stream_tell(GMimeStream * stream)268 stream_tell (GMimeStream *stream)
269 {
270 	return -1;
271 }
272 
273 static gint64
stream_length(GMimeStream * stream)274 stream_length (GMimeStream *stream)
275 {
276 	return -1;
277 }
278 
279 static GMimeStream *
stream_substream(GMimeStream * stream,gint64 start,gint64 end)280 stream_substream (GMimeStream *stream, gint64 start, gint64 end)
281 {
282 	return NULL;
283 }
284 
285 
286 /**
287  * g_mime_stream_pipe_new:
288  * @fd: a pipe descriptor
289  *
290  * Creates a new #GMimeStreamPipe object around @fd.
291  *
292  * Returns: a stream using @fd.
293  **/
294 GMimeStream *
g_mime_stream_pipe_new(int fd)295 g_mime_stream_pipe_new (int fd)
296 {
297 	GMimeStreamPipe *pipes;
298 
299 	pipes = g_object_newv (GMIME_TYPE_STREAM_PIPE, 0, NULL);
300 	g_mime_stream_construct (GMIME_STREAM (pipes), 0, -1);
301 	pipes->owner = TRUE;
302 	pipes->eos = FALSE;
303 	pipes->fd = fd;
304 
305 	return (GMimeStream *) pipes;
306 }
307 
308 
309 /**
310  * g_mime_stream_pipe_get_owner:
311  * @stream: a #GMimeStreamPipe
312  *
313  * Gets whether or not @stream owns the backend pipe descriptor.
314  *
315  * Returns: %TRUE if @stream owns the backend pipe descriptor or %FALSE
316  * otherwise.
317  **/
318 gboolean
g_mime_stream_pipe_get_owner(GMimeStreamPipe * stream)319 g_mime_stream_pipe_get_owner (GMimeStreamPipe *stream)
320 {
321 	g_return_val_if_fail (GMIME_IS_STREAM_PIPE (stream), FALSE);
322 
323 	return stream->owner;
324 }
325 
326 
327 /**
328  * g_mime_stream_pipe_set_owner:
329  * @stream: a #GMimeStreamPipe
330  * @owner: owner
331  *
332  * Sets whether or not @stream owns the backend pipe descriptor.
333  *
334  * Note: @owner should be %TRUE if the stream should close() the
335  * backend pipe descriptor when destroyed or %FALSE otherwise.
336  **/
337 void
g_mime_stream_pipe_set_owner(GMimeStreamPipe * stream,gboolean owner)338 g_mime_stream_pipe_set_owner (GMimeStreamPipe *stream, gboolean owner)
339 {
340 	g_return_if_fail (GMIME_IS_STREAM_PIPE (stream));
341 
342 	stream->owner = owner;
343 }
344