Imported Upstream version 2.66.6
[platform/upstream/glib.git] / gio / gunixoutputstream.c
1 /* GIO - GLib Input, Output and Streaming Library
2  * 
3  * Copyright (C) 2006-2007 Red Hat, Inc.
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
7  * License as published by the Free Software Foundation; either
8  * version 2.1 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
16  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
17  *
18  * Author: Alexander Larsson <alexl@redhat.com>
19  */
20
21 #include "config.h"
22
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <unistd.h>
26 #include <errno.h>
27 #include <stdio.h>
28 #include <fcntl.h>
29 #include <sys/uio.h>
30
31 #include <glib.h>
32 #include <glib/gstdio.h>
33 #include <glib/glib-unix.h>
34 #include "gioerror.h"
35 #include "gunixoutputstream.h"
36 #include "gcancellable.h"
37 #include "gasynchelper.h"
38 #include "gfiledescriptorbased.h"
39 #include "glibintl.h"
40 #include "gioprivate.h"
41
42
43 /**
44  * SECTION:gunixoutputstream
45  * @short_description: Streaming output operations for UNIX file descriptors
46  * @include: gio/gunixoutputstream.h
47  * @see_also: #GOutputStream
48  *
49  * #GUnixOutputStream implements #GOutputStream for writing to a UNIX
50  * file descriptor, including asynchronous operations. (If the file
51  * descriptor refers to a socket or pipe, this will use poll() to do
52  * asynchronous I/O. If it refers to a regular file, it will fall back
53  * to doing asynchronous I/O in another thread.)
54  *
55  * Note that `<gio/gunixoutputstream.h>` belongs to the UNIX-specific GIO
56  * interfaces, thus you have to use the `gio-unix-2.0.pc` pkg-config file
57  * when using it.
58  */
59
60 enum {
61   PROP_0,
62   PROP_FD,
63   PROP_CLOSE_FD
64 };
65
66 struct _GUnixOutputStreamPrivate {
67   int fd;
68   guint close_fd : 1;
69   guint is_pipe_or_socket : 1;
70 };
71
72 static void g_unix_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface);
73 static void g_unix_output_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface);
74
75 G_DEFINE_TYPE_WITH_CODE (GUnixOutputStream, g_unix_output_stream, G_TYPE_OUTPUT_STREAM,
76                          G_ADD_PRIVATE (GUnixOutputStream)
77                          G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_OUTPUT_STREAM,
78                                                 g_unix_output_stream_pollable_iface_init)
79                          G_IMPLEMENT_INTERFACE (G_TYPE_FILE_DESCRIPTOR_BASED,
80                                                 g_unix_output_stream_file_descriptor_based_iface_init)
81                          )
82
83 static void     g_unix_output_stream_set_property (GObject              *object,
84                                                    guint                 prop_id,
85                                                    const GValue         *value,
86                                                    GParamSpec           *pspec);
87 static void     g_unix_output_stream_get_property (GObject              *object,
88                                                    guint                 prop_id,
89                                                    GValue               *value,
90                                                    GParamSpec           *pspec);
91 static gssize   g_unix_output_stream_write        (GOutputStream        *stream,
92                                                    const void           *buffer,
93                                                    gsize                 count,
94                                                    GCancellable         *cancellable,
95                                                    GError              **error);
96 static gboolean g_unix_output_stream_writev       (GOutputStream        *stream,
97                                                    const GOutputVector  *vectors,
98                                                    gsize                 n_vectors,
99                                                    gsize                *bytes_written,
100                                                    GCancellable         *cancellable,
101                                                    GError              **error);
102 static gboolean g_unix_output_stream_close        (GOutputStream        *stream,
103                                                    GCancellable         *cancellable,
104                                                    GError              **error);
105
106 static gboolean g_unix_output_stream_pollable_can_poll      (GPollableOutputStream *stream);
107 static gboolean g_unix_output_stream_pollable_is_writable   (GPollableOutputStream *stream);
108 static GSource *g_unix_output_stream_pollable_create_source (GPollableOutputStream *stream,
109                                                              GCancellable         *cancellable);
110 static GPollableReturn g_unix_output_stream_pollable_writev_nonblocking (GPollableOutputStream  *stream,
111                                                                          const GOutputVector    *vectors,
112                                                                          gsize                   n_vectors,
113                                                                          gsize                  *bytes_written,
114                                                                          GError                **error);
115
116 static void
117 g_unix_output_stream_class_init (GUnixOutputStreamClass *klass)
118 {
119   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
120   GOutputStreamClass *stream_class = G_OUTPUT_STREAM_CLASS (klass);
121
122   gobject_class->get_property = g_unix_output_stream_get_property;
123   gobject_class->set_property = g_unix_output_stream_set_property;
124
125   stream_class->write_fn = g_unix_output_stream_write;
126   stream_class->writev_fn = g_unix_output_stream_writev;
127   stream_class->close_fn = g_unix_output_stream_close;
128
129    /**
130    * GUnixOutputStream:fd:
131    *
132    * The file descriptor that the stream writes to.
133    *
134    * Since: 2.20
135    */
136   g_object_class_install_property (gobject_class,
137                                    PROP_FD,
138                                    g_param_spec_int ("fd",
139                                                      P_("File descriptor"),
140                                                      P_("The file descriptor to write to"),
141                                                      G_MININT, G_MAXINT, -1,
142                                                      G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
143
144   /**
145    * GUnixOutputStream:close-fd:
146    *
147    * Whether to close the file descriptor when the stream is closed.
148    *
149    * Since: 2.20
150    */
151   g_object_class_install_property (gobject_class,
152                                    PROP_CLOSE_FD,
153                                    g_param_spec_boolean ("close-fd",
154                                                          P_("Close file descriptor"),
155                                                          P_("Whether to close the file descriptor when the stream is closed"),
156                                                          TRUE,
157                                                          G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
158 }
159
160 static void
161 g_unix_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface)
162 {
163   iface->can_poll = g_unix_output_stream_pollable_can_poll;
164   iface->is_writable = g_unix_output_stream_pollable_is_writable;
165   iface->create_source = g_unix_output_stream_pollable_create_source;
166   iface->writev_nonblocking = g_unix_output_stream_pollable_writev_nonblocking;
167 }
168
169 static void
170 g_unix_output_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface)
171 {
172   iface->get_fd = (int (*) (GFileDescriptorBased *))g_unix_output_stream_get_fd;
173 }
174
175 static void
176 g_unix_output_stream_set_property (GObject         *object,
177                                    guint            prop_id,
178                                    const GValue    *value,
179                                    GParamSpec      *pspec)
180 {
181   GUnixOutputStream *unix_stream;
182
183   unix_stream = G_UNIX_OUTPUT_STREAM (object);
184
185   switch (prop_id)
186     {
187     case PROP_FD:
188       unix_stream->priv->fd = g_value_get_int (value);
189       if (lseek (unix_stream->priv->fd, 0, SEEK_CUR) == -1 && errno == ESPIPE)
190         unix_stream->priv->is_pipe_or_socket = TRUE;
191       else
192         unix_stream->priv->is_pipe_or_socket = FALSE;
193       break;
194     case PROP_CLOSE_FD:
195       unix_stream->priv->close_fd = g_value_get_boolean (value);
196       break;
197     default:
198       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
199       break;
200     }
201 }
202
203 static void
204 g_unix_output_stream_get_property (GObject    *object,
205                                    guint       prop_id,
206                                    GValue     *value,
207                                    GParamSpec *pspec)
208 {
209   GUnixOutputStream *unix_stream;
210
211   unix_stream = G_UNIX_OUTPUT_STREAM (object);
212
213   switch (prop_id)
214     {
215     case PROP_FD:
216       g_value_set_int (value, unix_stream->priv->fd);
217       break;
218     case PROP_CLOSE_FD:
219       g_value_set_boolean (value, unix_stream->priv->close_fd);
220       break;
221     default:
222       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
223     }
224 }
225
226 static void
227 g_unix_output_stream_init (GUnixOutputStream *unix_stream)
228 {
229   unix_stream->priv = g_unix_output_stream_get_instance_private (unix_stream);
230   unix_stream->priv->fd = -1;
231   unix_stream->priv->close_fd = TRUE;
232 }
233
234 /**
235  * g_unix_output_stream_new:
236  * @fd: a UNIX file descriptor
237  * @close_fd: %TRUE to close the file descriptor when done
238  * 
239  * Creates a new #GUnixOutputStream for the given @fd. 
240  * 
241  * If @close_fd, is %TRUE, the file descriptor will be closed when 
242  * the output stream is destroyed.
243  * 
244  * Returns: a new #GOutputStream
245  **/
246 GOutputStream *
247 g_unix_output_stream_new (gint     fd,
248                           gboolean close_fd)
249 {
250   GUnixOutputStream *stream;
251
252   g_return_val_if_fail (fd != -1, NULL);
253
254   stream = g_object_new (G_TYPE_UNIX_OUTPUT_STREAM,
255                          "fd", fd,
256                          "close-fd", close_fd,
257                          NULL);
258   
259   return G_OUTPUT_STREAM (stream);
260 }
261
262 /**
263  * g_unix_output_stream_set_close_fd:
264  * @stream: a #GUnixOutputStream
265  * @close_fd: %TRUE to close the file descriptor when done
266  *
267  * Sets whether the file descriptor of @stream shall be closed
268  * when the stream is closed.
269  *
270  * Since: 2.20
271  */
272 void
273 g_unix_output_stream_set_close_fd (GUnixOutputStream *stream,
274                                    gboolean           close_fd)
275 {
276   g_return_if_fail (G_IS_UNIX_OUTPUT_STREAM (stream));
277
278   close_fd = close_fd != FALSE;
279   if (stream->priv->close_fd != close_fd)
280     {
281       stream->priv->close_fd = close_fd;
282       g_object_notify (G_OBJECT (stream), "close-fd");
283     }
284 }
285
286 /**
287  * g_unix_output_stream_get_close_fd:
288  * @stream: a #GUnixOutputStream
289  *
290  * Returns whether the file descriptor of @stream will be
291  * closed when the stream is closed.
292  *
293  * Returns: %TRUE if the file descriptor is closed when done
294  *
295  * Since: 2.20
296  */
297 gboolean
298 g_unix_output_stream_get_close_fd (GUnixOutputStream *stream)
299 {
300   g_return_val_if_fail (G_IS_UNIX_OUTPUT_STREAM (stream), FALSE);
301
302   return stream->priv->close_fd;
303 }
304
305 /**
306  * g_unix_output_stream_get_fd:
307  * @stream: a #GUnixOutputStream
308  *
309  * Return the UNIX file descriptor that the stream writes to.
310  *
311  * Returns: The file descriptor of @stream
312  *
313  * Since: 2.20
314  */
315 gint
316 g_unix_output_stream_get_fd (GUnixOutputStream *stream)
317 {
318   g_return_val_if_fail (G_IS_UNIX_OUTPUT_STREAM (stream), -1);
319
320   return stream->priv->fd;
321 }
322
323 static gssize
324 g_unix_output_stream_write (GOutputStream  *stream,
325                             const void     *buffer,
326                             gsize           count,
327                             GCancellable   *cancellable,
328                             GError        **error)
329 {
330   GUnixOutputStream *unix_stream;
331   gssize res = -1;
332   GPollFD poll_fds[2];
333   int nfds = 0;
334   int poll_ret;
335
336   unix_stream = G_UNIX_OUTPUT_STREAM (stream);
337
338   poll_fds[0].fd = unix_stream->priv->fd;
339   poll_fds[0].events = G_IO_OUT;
340   nfds++;
341
342   if (unix_stream->priv->is_pipe_or_socket &&
343       g_cancellable_make_pollfd (cancellable, &poll_fds[1]))
344     nfds++;
345
346   while (1)
347     {
348       int errsv;
349
350       poll_fds[0].revents = poll_fds[1].revents = 0;
351       do
352         {
353           poll_ret = g_poll (poll_fds, nfds, -1);
354           errsv = errno;
355         }
356       while (poll_ret == -1 && errsv == EINTR);
357
358       if (poll_ret == -1)
359         {
360           g_set_error (error, G_IO_ERROR,
361                        g_io_error_from_errno (errsv),
362                        _("Error writing to file descriptor: %s"),
363                        g_strerror (errsv));
364           break;
365         }
366
367       if (g_cancellable_set_error_if_cancelled (cancellable, error))
368         break;
369
370       if (!poll_fds[0].revents)
371         continue;
372
373       res = write (unix_stream->priv->fd, buffer, count);
374       errsv = errno;
375       if (res == -1)
376         {
377           if (errsv == EINTR || errsv == EAGAIN)
378             continue;
379
380           g_set_error (error, G_IO_ERROR,
381                        g_io_error_from_errno (errsv),
382                        _("Error writing to file descriptor: %s"),
383                        g_strerror (errsv));
384         }
385
386       break;
387     }
388
389   if (nfds == 2)
390     g_cancellable_release_fd (cancellable);
391   return res;
392 }
393
394 /* Macro to check if struct iovec and GOutputVector have the same ABI */
395 #define G_OUTPUT_VECTOR_IS_IOVEC (sizeof (struct iovec) == sizeof (GOutputVector) && \
396       G_SIZEOF_MEMBER (struct iovec, iov_base) == G_SIZEOF_MEMBER (GOutputVector, buffer) && \
397       G_STRUCT_OFFSET (struct iovec, iov_base) == G_STRUCT_OFFSET (GOutputVector, buffer) && \
398       G_SIZEOF_MEMBER (struct iovec, iov_len) == G_SIZEOF_MEMBER (GOutputVector, size) && \
399       G_STRUCT_OFFSET (struct iovec, iov_len) == G_STRUCT_OFFSET (GOutputVector, size))
400
401 static gboolean
402 g_unix_output_stream_writev (GOutputStream        *stream,
403                              const GOutputVector  *vectors,
404                              gsize                 n_vectors,
405                              gsize                *bytes_written,
406                              GCancellable         *cancellable,
407                              GError              **error)
408 {
409   GUnixOutputStream *unix_stream;
410   gssize res = -1;
411   GPollFD poll_fds[2];
412   int nfds = 0;
413   int poll_ret;
414   struct iovec *iov;
415
416   if (bytes_written)
417     *bytes_written = 0;
418
419   /* Clamp the number of vectors if more given than we can write in one go.
420    * The caller has to handle short writes anyway.
421    */
422   if (n_vectors > G_IOV_MAX)
423     n_vectors = G_IOV_MAX;
424
425   unix_stream = G_UNIX_OUTPUT_STREAM (stream);
426
427   if (G_OUTPUT_VECTOR_IS_IOVEC)
428     {
429       /* ABI is compatible */
430       iov = (struct iovec *) vectors;
431     }
432   else
433     {
434       gsize i;
435
436       /* ABI is incompatible */
437       iov = g_newa (struct iovec, n_vectors);
438       for (i = 0; i < n_vectors; i++)
439         {
440           iov[i].iov_base = (void *)vectors[i].buffer;
441           iov[i].iov_len = vectors[i].size;
442         }
443     }
444
445   poll_fds[0].fd = unix_stream->priv->fd;
446   poll_fds[0].events = G_IO_OUT;
447   nfds++;
448
449   if (unix_stream->priv->is_pipe_or_socket &&
450       g_cancellable_make_pollfd (cancellable, &poll_fds[1]))
451     nfds++;
452
453   while (1)
454     {
455       int errsv;
456
457       poll_fds[0].revents = poll_fds[1].revents = 0;
458       do
459         {
460           poll_ret = g_poll (poll_fds, nfds, -1);
461           errsv = errno;
462         }
463       while (poll_ret == -1 && errsv == EINTR);
464
465       if (poll_ret == -1)
466         {
467           g_set_error (error, G_IO_ERROR,
468                        g_io_error_from_errno (errsv),
469                        _("Error writing to file descriptor: %s"),
470                        g_strerror (errsv));
471           break;
472         }
473
474       if (g_cancellable_set_error_if_cancelled (cancellable, error))
475         break;
476
477       if (!poll_fds[0].revents)
478         continue;
479
480       res = writev (unix_stream->priv->fd, iov, n_vectors);
481       errsv = errno;
482       if (res == -1)
483         {
484           if (errsv == EINTR || errsv == EAGAIN)
485             continue;
486
487           g_set_error (error, G_IO_ERROR,
488                        g_io_error_from_errno (errsv),
489                        _("Error writing to file descriptor: %s"),
490                        g_strerror (errsv));
491         }
492
493       if (bytes_written)
494         *bytes_written = res;
495
496       break;
497     }
498
499   if (nfds == 2)
500     g_cancellable_release_fd (cancellable);
501   return res != -1;
502 }
503
504 static gboolean
505 g_unix_output_stream_close (GOutputStream  *stream,
506                             GCancellable   *cancellable,
507                             GError        **error)
508 {
509   GUnixOutputStream *unix_stream;
510   int res;
511
512   unix_stream = G_UNIX_OUTPUT_STREAM (stream);
513
514   if (!unix_stream->priv->close_fd)
515     return TRUE;
516   
517   /* This might block during the close. Doesn't seem to be a way to avoid it though. */
518   res = close (unix_stream->priv->fd);
519   if (res == -1)
520     {
521       int errsv = errno;
522
523       g_set_error (error, G_IO_ERROR,
524                    g_io_error_from_errno (errsv),
525                    _("Error closing file descriptor: %s"),
526                    g_strerror (errsv));
527     }
528
529   return res != -1;
530 }
531
532 static gboolean
533 g_unix_output_stream_pollable_can_poll (GPollableOutputStream *stream)
534 {
535   return G_UNIX_OUTPUT_STREAM (stream)->priv->is_pipe_or_socket;
536 }
537
538 static gboolean
539 g_unix_output_stream_pollable_is_writable (GPollableOutputStream *stream)
540 {
541   GUnixOutputStream *unix_stream = G_UNIX_OUTPUT_STREAM (stream);
542   GPollFD poll_fd;
543   gint result;
544
545   poll_fd.fd = unix_stream->priv->fd;
546   poll_fd.events = G_IO_OUT;
547   poll_fd.revents = 0;
548
549   do
550     result = g_poll (&poll_fd, 1, 0);
551   while (result == -1 && errno == EINTR);
552
553   return poll_fd.revents != 0;
554 }
555
556 static GSource *
557 g_unix_output_stream_pollable_create_source (GPollableOutputStream *stream,
558                                              GCancellable          *cancellable)
559 {
560   GUnixOutputStream *unix_stream = G_UNIX_OUTPUT_STREAM (stream);
561   GSource *inner_source, *cancellable_source, *pollable_source;
562
563   pollable_source = g_pollable_source_new (G_OBJECT (stream));
564
565   inner_source = g_unix_fd_source_new (unix_stream->priv->fd, G_IO_OUT);
566   g_source_set_dummy_callback (inner_source);
567   g_source_add_child_source (pollable_source, inner_source);
568   g_source_unref (inner_source);
569
570   if (cancellable)
571     {
572       cancellable_source = g_cancellable_source_new (cancellable);
573       g_source_set_dummy_callback (cancellable_source);
574       g_source_add_child_source (pollable_source, cancellable_source);
575       g_source_unref (cancellable_source);
576     }
577
578   return pollable_source;
579 }
580
581 static GPollableReturn
582 g_unix_output_stream_pollable_writev_nonblocking (GPollableOutputStream  *stream,
583                                                   const GOutputVector    *vectors,
584                                                   gsize                   n_vectors,
585                                                   gsize                  *bytes_written,
586                                                   GError                **error)
587 {
588   GUnixOutputStream *unix_stream = G_UNIX_OUTPUT_STREAM (stream);
589   struct iovec *iov;
590   gssize res = -1;
591
592   if (!g_pollable_output_stream_is_writable (stream))
593     {
594       *bytes_written = 0;
595       return G_POLLABLE_RETURN_WOULD_BLOCK;
596     }
597
598   /* Clamp the number of vectors if more given than we can write in one go.
599    * The caller has to handle short writes anyway.
600    */
601   if (n_vectors > G_IOV_MAX)
602     n_vectors = G_IOV_MAX;
603
604   if (G_OUTPUT_VECTOR_IS_IOVEC)
605     {
606       /* ABI is compatible */
607       iov = (struct iovec *) vectors;
608     }
609   else
610     {
611       gsize i;
612
613       /* ABI is incompatible */
614       iov = g_newa (struct iovec, n_vectors);
615       for (i = 0; i < n_vectors; i++)
616         {
617           iov[i].iov_base = (void *)vectors[i].buffer;
618           iov[i].iov_len = vectors[i].size;
619         }
620     }
621
622   while (1)
623     {
624       int errsv;
625
626       res = writev (unix_stream->priv->fd, iov, n_vectors);
627       errsv = errno;
628       if (res == -1)
629         {
630           if (errsv == EINTR)
631             continue;
632
633           g_set_error (error, G_IO_ERROR,
634                        g_io_error_from_errno (errsv),
635                        _("Error writing to file descriptor: %s"),
636                        g_strerror (errsv));
637         }
638
639       if (bytes_written)
640         *bytes_written = res;
641
642       break;
643     }
644
645   return res != -1 ? G_POLLABLE_RETURN_OK : G_POLLABLE_RETURN_FAILED;
646 }